From d748bd0dcfb196fb47b8e52b92a9c2ee71b53110 Mon Sep 17 00:00:00 2001 From: emmfox <50134580+emmfox@users.noreply.github.com> Date: Wed, 22 May 2019 11:23:19 +0800 Subject: [PATCH 01/74] =?UTF-8?q?#1052=20=E4=BF=AE=E6=AD=A3=E4=BC=81?= =?UTF-8?q?=E4=B8=9A=E5=BE=AE=E4=BF=A1=E9=83=A8=E9=97=A8=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E4=B8=AD=E7=9A=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 修正部门管理接口中注释中错误的部分 * 完善部门管理接口中不符合javadoc的部分注释 --- .../weixin/cp/api/WxCpDepartmentService.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java index 82e571ac5b..8af1d3041a 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java @@ -19,7 +19,7 @@ public interface WxCpDepartmentService { *
    * 部门管理接口 - 创建部门.
    * 最多支持创建500个部门
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
+   * 详情请见: https://work.weixin.qq.com/api/doc#90000/90135/90205
    * 
* * @param depart 部门 @@ -30,19 +30,20 @@ public interface WxCpDepartmentService { /** *
-   * 部门管理接口 - 查询部门.
-   * 详情请见: http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E9%83%A8%E9%97%A8#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E5.88.97.E8.A1.A8
+   * 部门管理接口 - 获取部门列表.
+   * 详情请见: https://work.weixin.qq.com/api/doc#90000/90135/90208
    * 
* * @param id 部门id。获取指定部门及其下的子部门。非必需,可为null + * @return 获取的部门列表 * @throws WxErrorException 异常 */ List list(Long id) throws WxErrorException; /** *
-   * 部门管理接口 - 修改部门名.
-   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
+   * 部门管理接口 - 更新部门.
+   * 详情请见: https://work.weixin.qq.com/api/doc#90000/90135/90206
    * 如果id为0(未部门),1(黑名单),2(星标组),或者不存在的id,微信会返回系统繁忙的错误
    * 
* @@ -54,6 +55,8 @@ public interface WxCpDepartmentService { /** *
    * 部门管理接口 - 删除部门.
+   * 详情请见: https://work.weixin.qq.com/api/doc#90000/90135/90207
+   * 应用须拥有指定部门的管理权限
    * 
* * @param departId 部门id From 001a2742c6753b00394503850994d77b1e81a049 Mon Sep 17 00:00:00 2001 From: feye Date: Fri, 24 May 2019 13:42:13 +0800 Subject: [PATCH 02/74] =?UTF-8?q?#493=20=E4=BC=81=E4=B8=9A=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E5=A2=9E=E5=8A=A0=E7=AC=AC=E4=B8=89=E6=96=B9=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E5=BC=80=E5=8F=91=E6=8E=A5=E5=8F=A3=E7=9A=84=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chanjar/weixin/cp/api/WxCpTpService.java | 169 ++++++++++++ .../cp/api/impl/BaseWxCpTpServiceImpl.java | 244 +++++++++++++++++ .../cp/api/impl/WxCpServiceOnTpImpl.java | 37 +++ .../WxCpTpServiceApacheHttpClientImpl.java | 114 ++++++++ .../weixin/cp/api/impl/WxCpTpServiceImpl.java | 12 + .../me/chanjar/weixin/cp/bean/WxCpTpCorp.java | 42 +++ .../weixin/cp/bean/WxCpTpXmlMessage.java | 68 +++++ .../weixin/cp/bean/WxCpTpXmlPackage.java | 55 ++++ .../weixin/cp/config/WxCpTpConfigStorage.java | 72 +++++ .../config/WxCpTpInMemoryConfigStorage.java | 230 ++++++++++++++++ .../cp/util/crypto/WxCpTpCryptUtil.java | 52 ++++ .../cp/util/xml/XStreamTransformer.java | 252 ++++++++++-------- 12 files changed, 1230 insertions(+), 117 deletions(-) create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImpl.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOnTpImpl.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceApacheHttpClientImpl.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceImpl.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpCorp.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpXmlMessage.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpXmlPackage.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpInMemoryConfigStorage.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpTpCryptUtil.java diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java new file mode 100644 index 0000000000..741d27de58 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java @@ -0,0 +1,169 @@ +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.error.WxErrorException; +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.cp.bean.WxCpMaJsCode2SessionResult; +import me.chanjar.weixin.cp.bean.WxCpTpCorp; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; +import me.chanjar.weixin.cp.config.WxCpTpConfigStorage; + +/** + * 微信第三方应用API的Service + * @author zhenjun cai + */ +public interface WxCpTpService { + String JSCODE_TO_SESSION_URL = "https://qyapi.weixin.qq.com/cgi-bin/service/miniprogram/jscode2session"; + String GET_CORP_TOKEN = "https://qyapi.weixin.qq.com/cgi-bin/service/get_corp_token"; + String GET_PERMANENT_CODE = "https://qyapi.weixin.qq.com/cgi-bin/service/get_permanent_code"; + /** + *
+   * 验证推送过来的消息的正确性
+   * 详情请见: https://work.weixin.qq.com/api/doc#90000/90139/90968/消息体签名校验
+   * 
+ * + * @param msgSignature 消息签名 + * @param timestamp 时间戳 + * @param nonce 随机数 + * @param data 微信传输过来的数据,有可能是echoStr,有可能是xml消息 + */ + boolean checkSignature(String msgSignature, String timestamp, String nonce, String data); + + /** + * 获取suite_access_token, 不强制刷新suite_access_token + * + * @see #getSuiteAccessToken(boolean) + */ + String getSuiteAccessToken() throws WxErrorException; + + /** + *
+   * 获取suite_access_token,本方法线程安全
+   * 且在多线程同时刷新时只刷新一次,避免超出2000次/日的调用次数上限
+   * 另:本service的所有方法都会在suite_access_token过期是调用此方法
+   * 程序员在非必要情况下尽量不要主动调用此方法
+   * 详情请见: https://work.weixin.qq.com/api/doc#90001/90143/90600
+   * 
+ * + * @param forceRefresh 强制刷新 + */ + String getSuiteAccessToken(boolean forceRefresh) throws WxErrorException; + + /** + * 获得suite_ticket,不强制刷新suite_ticket + * + * @see #getSuiteTicket(boolean) + */ + String getSuiteTicket() throws WxErrorException; + + /** + *
+   * 获得suite_ticket
+   * 由于suite_ticket是微信服务器定时推送(每10分钟),不能主动获取,如果碰到过期只能抛异常
+   *
+   * 详情请见:https://work.weixin.qq.com/api/doc#90001/90143/90628
+   * 
+ * + * @param forceRefresh 强制刷新 + */ + String getSuiteTicket(boolean forceRefresh) throws WxErrorException; + + /** + * 小程序登录凭证校验 + * + * @param jsCode 登录时获取的 code + */ + WxCpMaJsCode2SessionResult jsCode2Session(String jsCode) throws WxErrorException; + + /** + * 获取企业凭证 + * @param authCorpid 授权方corpid + * @param permanentCode 永久授权码,通过get_permanent_code获取 + */ + WxAccessToken getCorpToken(String authCorpid, String permanentCode) throws WxErrorException; + + /** + * 获取企业永久授权码 + * @param authCode + * @return + */ + WxCpTpCorp getPermanentCode(String authCode) throws WxErrorException; + + /** + * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求 + * + * @param url 接口地址 + * @param queryParam 请求参数 + */ + String get(String url, String queryParam) throws WxErrorException; + + /** + * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求 + * + * @param url 接口地址 + * @param postData 请求body字符串 + */ + String post(String url, String postData) throws WxErrorException; + + /** + *
+   * Service没有实现某个API的时候,可以用这个,
+   * 比{@link #get}和{@link #post}方法更灵活,可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。
+   * 可以参考,{@link MediaUploadRequestExecutor}的实现方法
+   * 
+ * + * @param executor 执行器 + * @param uri 请求地址 + * @param data 参数 + * @param 请求值类型 + * @param 返回值类型 + */ + T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; + + /** + *
+   * 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试
+   * 默认:1000ms
+   * 
+ * + * @param retrySleepMillis 重试休息时间 + */ + void setRetrySleepMillis(int retrySleepMillis); + + /** + *
+   * 设置当微信系统响应系统繁忙时,最大重试次数
+   * 默认:5次
+   * 
+ * + * @param maxRetryTimes 最大重试次数 + */ + void setMaxRetryTimes(int maxRetryTimes); + + /** + * 初始化http请求对象 + */ + void initHttp(); + + /** + * 获取WxMpConfigStorage 对象 + * + * @return WxMpConfigStorage + */ + WxCpTpConfigStorage getWxCpTpConfigStorage(); + + /** + * 注入 {@link WxCpTpConfigStorage} 的实现 + * + * @param wxConfigProvider 配置对象 + */ + void setWxCpTpConfigStorage(WxCpTpConfigStorage wxConfigProvider); + + /** + * http请求对象 + */ + RequestHttp getRequestHttp(); + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImpl.java new file mode 100644 index 0000000000..837c355e4d --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImpl.java @@ -0,0 +1,244 @@ +package me.chanjar.weixin.cp.api.impl; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Joiner; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import me.chanjar.weixin.common.WxType; +import me.chanjar.weixin.common.bean.WxAccessToken; +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.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.cp.api.WxCpService; +import me.chanjar.weixin.cp.api.WxCpTpService; +import me.chanjar.weixin.cp.bean.WxCpMaJsCode2SessionResult; +import me.chanjar.weixin.cp.bean.WxCpTpCorp; +import me.chanjar.weixin.cp.config.WxCpTpConfigStorage; + +/** + * @author zhenjun cai + */ +public abstract class BaseWxCpTpServiceImpl implements WxCpTpService, RequestHttp { + protected final Logger log = LoggerFactory.getLogger(this.getClass()); + + /** + * 全局的是否正在刷新access token的锁 + */ + protected final Object globalSuiteAccessTokenRefreshLock = new Object(); + + /** + * 全局的是否正在刷新jsapi_ticket的锁 + */ + protected final Object globalSuiteTicketRefreshLock = new Object(); + + + protected WxCpTpConfigStorage configStorage; + + + /** + * 临时文件目录 + */ + private File tmpDirFile; + private int retrySleepMillis = 1000; + private int maxRetryTimes = 5; + + @Override + public boolean checkSignature(String msgSignature, String timestamp, String nonce, String data) { + try { + return SHA1.gen(this.configStorage.getToken(), timestamp, nonce, data) + .equals(msgSignature); + } catch (Exception e) { + this.log.error("Checking signature failed, and the reason is :" + e.getMessage()); + return false; + } + } + + @Override + public String getSuiteAccessToken() throws WxErrorException { + return getSuiteAccessToken(false); + } + + @Override + public String getSuiteTicket() throws WxErrorException { + return getSuiteTicket(false); + } + + @Override + public String getSuiteTicket(boolean forceRefresh) throws WxErrorException { +// suite ticket由微信服务器推送,不能强制刷新 +// if (forceRefresh) { +// this.configStorage.expireSuiteTicket(); +// } + + if (this.configStorage.isSuiteTicketExpired()) { +// 本地suite ticket 不存在或者过期 + WxError wxError = WxError.fromJson("{\"errcode\":40085, \"errmsg\":\"invaild suite ticket\"}", WxType.CP); + throw new WxErrorException(wxError); + } + return this.configStorage.getSuiteTicket(); + } + + + @Override + public WxCpMaJsCode2SessionResult jsCode2Session(String jsCode) throws WxErrorException { + Map params = new HashMap<>(2); + params.put("js_code", jsCode); + params.put("grant_type", "authorization_code"); + + String result = this.get(JSCODE_TO_SESSION_URL, Joiner.on("&").withKeyValueSeparator("=").join(params)); + return WxCpMaJsCode2SessionResult.fromJson(result); + } + + + @Override + public WxAccessToken getCorpToken(String authCorpid, String permanentCode) throws WxErrorException { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("auth_corpid", authCorpid); + jsonObject.addProperty("permanent_code", permanentCode); + String result = post(GET_CORP_TOKEN, jsonObject.toString()); + + return WxAccessToken.fromJson(result); + } + + + @Override + public WxCpTpCorp getPermanentCode(String authCode) throws WxErrorException { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("auth_code", authCode); + + String result = post(GET_PERMANENT_CODE, jsonObject.toString()); + jsonObject = new JsonParser().parse(result).getAsJsonObject(); + WxCpTpCorp wxCpTpCorp = WxCpTpCorp.fromJson(jsonObject.get("auth_corp_info").getAsString()); + wxCpTpCorp.setPermanentCode(jsonObject.get("permanent_code").getAsString()); + return wxCpTpCorp; + } + + @Override + public String get(String url, String queryParam) throws WxErrorException { + return execute(SimpleGetRequestExecutor.create(this), url, queryParam); + } + + @Override + public String post(String url, String postData) throws WxErrorException { + return execute(SimplePostRequestExecutor.create(this), url, postData); + } + + /** + * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求. + */ + @Override + public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException { + int retryTimes = 0; + do { + try { + return this.executeInternal(executor, uri, data); + } catch (WxErrorException e) { + if (retryTimes + 1 > this.maxRetryTimes) { + this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); + //最后一次重试失败后,直接抛出异常,不再等待 + throw new RuntimeException("微信服务端异常,超出重试次数"); + } + + WxError error = e.getError(); + /* + * -1 系统繁忙, 1000ms后重试 + */ + if (error.getErrorCode() == -1) { + int sleepMillis = this.retrySleepMillis * (1 << retryTimes); + try { + this.log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1); + Thread.sleep(sleepMillis); + } catch (InterruptedException e1) { + Thread.currentThread().interrupt(); + } + } else { + throw e; + } + } + } while (retryTimes++ < this.maxRetryTimes); + + this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes); + throw new RuntimeException("微信服务端异常,超出重试次数"); + } + + protected T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException { + E dataForLog = DataUtils.handleDataWithSecret(data); + + if (uri.contains("suite_access_token=")) { + throw new IllegalArgumentException("uri参数中不允许有suite_access_token: " + uri); + } + String suiteAccessToken = getSuiteAccessToken(false); + + String uriWithAccessToken = uri + (uri.contains("?") ? "&" : "?") + "suite_access_token=" + suiteAccessToken; + + try { + T result = executor.execute(uriWithAccessToken, data); + this.log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result); + return result; + } catch (WxErrorException e) { + WxError error = e.getError(); + /* + * 发生以下情况时尝试刷新suite_access_token + * 42009 suite_access_token已过期 + */ + if (error.getErrorCode() == 42009) { + // 强制设置wxCpTpConfigStorage它的suite access token过期了,这样在下一次请求里就会刷新suite access token + this.configStorage.expireSuiteAccessToken(); + return execute(executor, uri, data); + } + + if (error.getErrorCode() != 0) { + this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error); + throw new WxErrorException(error, e); + } + return null; + } catch (IOException e) { + this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage()); + throw new RuntimeException(e); + } + } + + @Override + public void setWxCpTpConfigStorage(WxCpTpConfigStorage wxConfigProvider) { + this.configStorage = wxConfigProvider; + this.initHttp(); + } + + @Override + public void setRetrySleepMillis(int retrySleepMillis) { + this.retrySleepMillis = retrySleepMillis; + } + + + @Override + public void setMaxRetryTimes(int maxRetryTimes) { + this.maxRetryTimes = maxRetryTimes; + } + + public File getTmpDirFile() { + return this.tmpDirFile; + } + + public void setTmpDirFile(File tmpDirFile) { + this.tmpDirFile = tmpDirFile; + } + + @Override + public RequestHttp getRequestHttp() { + return this; + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOnTpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOnTpImpl.java new file mode 100644 index 0000000000..1b7a67c6ea --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOnTpImpl.java @@ -0,0 +1,37 @@ +package me.chanjar.weixin.cp.api.impl; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.cp.api.WxCpTpService; + +/** + *
+ *  默认接口实现类,使用apache httpclient实现,配合第三方应用service使用
+ * Created by zhenjun cai.
+ * 
+ * + * @author Binary Wang + */ +public class WxCpServiceOnTpImpl extends WxCpServiceApacheHttpClientImpl { + //第三方应用service + WxCpTpService wxCpTpService; + + public void setWxCpTpService(WxCpTpService wxCpTpService) { + this.wxCpTpService = wxCpTpService; + } + + @Override + public String getAccessToken(boolean forceRefresh) throws WxErrorException { + if (!this.configStorage.isAccessTokenExpired() && !forceRefresh) { + return this.configStorage.getAccessToken(); + } + //access token通过第三方应用service获取 + //corpSecret对应企业永久授权码 + WxAccessToken accessToken = wxCpTpService.getCorpToken(this.configStorage.getCorpId(), this.configStorage.getCorpSecret()); + + this.configStorage.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); + return this.configStorage.getAccessToken(); + } + + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceApacheHttpClientImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceApacheHttpClientImpl.java new file mode 100644 index 0000000000..0b8a134d48 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceApacheHttpClientImpl.java @@ -0,0 +1,114 @@ +package me.chanjar.weixin.cp.api.impl; + + +import java.io.IOException; + +import org.apache.http.Consts; +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.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.BasicResponseHandler; +import org.apache.http.impl.client.CloseableHttpClient; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +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.http.HttpType; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; +import me.chanjar.weixin.cp.config.WxCpTpConfigStorage; + +public class WxCpTpServiceApacheHttpClientImpl extends BaseWxCpTpServiceImpl { + protected CloseableHttpClient httpClient; + protected HttpHost httpProxy; + + @Override + public CloseableHttpClient getRequestHttpClient() { + return httpClient; + } + + @Override + public HttpHost getRequestHttpProxy() { + return httpProxy; + } + + @Override + public HttpType getRequestType() { + return HttpType.APACHE_HTTP; + } + + @Override + public String getSuiteAccessToken(boolean forceRefresh) throws WxErrorException { + if (!this.configStorage.isSuiteAccessTokenExpired() && !forceRefresh) { + return this.configStorage.getSuiteAccessToken(); + } + + synchronized (this.globalSuiteAccessTokenRefreshLock) { + String url = "https://qyapi.weixin.qq.com/cgi-bin/service/get_suite_token"; + try { + HttpPost httpPost = new HttpPost(url); + if (this.httpProxy != null) { + RequestConfig config = RequestConfig.custom() + .setProxy(this.httpProxy).build(); + httpPost.setConfig(config); + } + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("suite_id", this.configStorage.getSuiteId()); + jsonObject.addProperty("suite_secret", this.configStorage.getSuiteSecret()); + jsonObject.addProperty("suite_ticket", this.getSuiteTicket()); + StringEntity entity = new StringEntity(jsonObject.toString(), Consts.UTF_8); + httpPost.setEntity(entity); + + String resultContent; + try (CloseableHttpClient httpclient = getRequestHttpClient(); + CloseableHttpResponse response = httpclient.execute(httpPost)) { + resultContent = new BasicResponseHandler().handleResponse(response); + } finally { + httpPost.releaseConnection(); + } + WxError error = WxError.fromJson(resultContent, WxType.CP); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + jsonObject = new JsonParser().parse(resultContent).getAsJsonObject(); + String suiteAccussToken = jsonObject.get("suite_access_token").getAsString(); + Integer expiresIn = jsonObject.get("expires_in").getAsInt(); + this.configStorage.updateSuiteAccessToken(suiteAccussToken, expiresIn); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return this.configStorage.getSuiteAccessToken(); + } + + @Override + public void initHttp() { + ApacheHttpClientBuilder apacheHttpClientBuilder = this.configStorage + .getApacheHttpClientBuilder(); + if (null == apacheHttpClientBuilder) { + apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get(); + } + + apacheHttpClientBuilder.httpProxyHost(this.configStorage.getHttpProxyHost()) + .httpProxyPort(this.configStorage.getHttpProxyPort()) + .httpProxyUsername(this.configStorage.getHttpProxyUsername()) + .httpProxyPassword(this.configStorage.getHttpProxyPassword()); + + if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) { + this.httpProxy = new HttpHost(this.configStorage.getHttpProxyHost(), this.configStorage.getHttpProxyPort()); + } + + this.httpClient = apacheHttpClientBuilder.build(); + } + + @Override + public WxCpTpConfigStorage getWxCpTpConfigStorage() { + return this.configStorage; + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceImpl.java new file mode 100644 index 0000000000..538209b77a --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceImpl.java @@ -0,0 +1,12 @@ +package me.chanjar.weixin.cp.api.impl; + +/** + *
+ *  默认接口实现类,使用apache httpclient实现
+ * Created by zhenjun cai.
+ * 
+ * + * @author Binary Wang + */ +public class WxCpTpServiceImpl extends WxCpTpServiceApacheHttpClientImpl { +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpCorp.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpCorp.java new file mode 100644 index 0000000000..9ca59b843d --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpCorp.java @@ -0,0 +1,42 @@ +package me.chanjar.weixin.cp.bean; + +import java.io.Serializable; + +import com.google.gson.annotations.SerializedName; + +import lombok.Data; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +/** + * 微信部门. + * + * @author Daniel Qian + */ +@Data +public class WxCpTpCorp implements Serializable { + + private static final long serialVersionUID = -5028321625140879571L; + @SerializedName("corpid") + private String corpId; + @SerializedName("corp_name") + private String corpName; + @SerializedName("corp_full_name") + private String corpFullName; + @SerializedName("corp_type") + private String corpType; + @SerializedName("corp_square_logo_url") + private String corpSquareLogoUrl; + @SerializedName("corp_user_max") + private String corpUserMax; + @SerializedName("permanent_code") + private String permanentCode; + + public static WxCpTpCorp fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpTpCorp.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpXmlMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpXmlMessage.java new file mode 100644 index 0000000000..53e068dbfe --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpXmlMessage.java @@ -0,0 +1,68 @@ +package me.chanjar.weixin.cp.bean; + +import java.io.Serializable; +import java.util.Map; + +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.XmlUtils; +import me.chanjar.weixin.common.util.crypto.WxCryptUtil; +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.config.WxCpTpConfigStorage; +import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; +import me.chanjar.weixin.cp.util.xml.XStreamTransformer; + +/** + * 回调推送的message + * https://work.weixin.qq.com/api/doc#90001/90143/90612 + * + * @author zhenjun cai + */ +@XStreamAlias("xml") +@Slf4j +@Data +public class WxCpTpXmlMessage implements Serializable { + + private static final long serialVersionUID = 6031833682211475786L; + /** + * 使用dom4j解析的存放所有xml属性和值的map. + */ + private Map allFieldsMap; + + @XStreamAlias("SuiteId") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String suiteId; + + @XStreamAlias("InfoType") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String infoType; + + @XStreamAlias("TimeStamp") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String timeStamp; + + @XStreamAlias("SuiteTicket") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String suiteTicket; + + @XStreamAlias("AuthCode") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String authCode; + + public static WxCpTpXmlMessage fromXml(String xml) { + //修改微信变态的消息内容格式,方便解析 + //xml = xml.replace("", ""); + final WxCpTpXmlMessage xmlPackage = XStreamTransformer.fromXml(WxCpTpXmlMessage.class, xml); + xmlPackage.setAllFieldsMap(XmlUtils.xml2Map(xml)); + return xmlPackage; + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpXmlPackage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpXmlPackage.java new file mode 100644 index 0000000000..82c33f5238 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpXmlPackage.java @@ -0,0 +1,55 @@ +package me.chanjar.weixin.cp.bean; + +import java.io.Serializable; +import java.util.Map; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamConverter; +import lombok.Data; +import me.chanjar.weixin.common.util.XmlUtils; +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.util.crypto.WxCpCryptUtil; +import me.chanjar.weixin.cp.util.xml.XStreamTransformer; + +/** + * 回调消息包. + * https://work.weixin.qq.com/api/doc#90001/90143/91116 + * + * @author zhenjun cai + */ +@XStreamAlias("xml") +@Data +public class WxCpTpXmlPackage implements Serializable { + + private static final long serialVersionUID = 6031833682211475786L; + /** + * 使用dom4j解析的存放所有xml属性和值的map. + */ + private Map allFieldsMap; + + @XStreamAlias("ToUserName") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String toUserName; + + @XStreamAlias("AgentID") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String agentId; + + @XStreamAlias("Encrypt") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String msgEncrypt; + + public static WxCpTpXmlPackage fromXml(String xml) { + //修改微信变态的消息内容格式,方便解析 + //xml = xml.replace("", ""); + final WxCpTpXmlPackage xmlPackage = XStreamTransformer.fromXml(WxCpTpXmlPackage.class, xml); + xmlPackage.setAllFieldsMap(XmlUtils.xml2Map(xml)); + return xmlPackage; + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java new file mode 100644 index 0000000000..a132dd1024 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java @@ -0,0 +1,72 @@ +package me.chanjar.weixin.cp.config; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; + +import java.io.File; + +/** + * 微信客户端(第三方应用)配置存储 + * + * @author zhenjun cai + */ +public interface WxCpTpConfigStorage { + + String getSuiteAccessToken(); + + boolean isSuiteAccessTokenExpired(); + + /** + * 强制将suite access token过期掉 + */ + void expireSuiteAccessToken(); + + void updateSuiteAccessToken(WxAccessToken suiteAccessToken); + + void updateSuiteAccessToken(String suiteAccessToken, int expiresIn); + + String getSuiteTicket(); + + boolean isSuiteTicketExpired(); + + /** + * 强制将suite ticket过期掉 + */ + void expireSuiteTicket(); + + /** + * 应该是线程安全的 + */ + void updateSuiteTicket(String suiteTicket, int expiresInSeconds); + + String getCorpId(); + + String getCorpSecret(); + + String getSuiteId(); + + String getSuiteSecret(); + + String getToken(); + + String getAesKey(); + + long getExpiresTime(); + + String getHttpProxyHost(); + + int getHttpProxyPort(); + + String getHttpProxyUsername(); + + String getHttpProxyPassword(); + + File getTmpDirFile(); + + /** + * http client builder + * + * @return ApacheHttpClientBuilder + */ + ApacheHttpClientBuilder getApacheHttpClientBuilder(); +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpInMemoryConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpInMemoryConfigStorage.java new file mode 100644 index 0000000000..c135c95b7f --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpInMemoryConfigStorage.java @@ -0,0 +1,230 @@ +package me.chanjar.weixin.cp.config; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.io.File; + +/** + * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 + * + * @author Daniel Qian + */ +public class WxCpTpInMemoryConfigStorage implements WxCpTpConfigStorage { + protected volatile String corpId; + protected volatile String corpSecret; + + protected volatile String suiteId; + protected volatile String suiteSecret; + + protected volatile String token; + protected volatile String suiteAccessToken; + protected volatile String aesKey; + protected volatile long expiresTime; + + protected volatile String oauth2redirectUri; + + protected volatile String httpProxyHost; + protected volatile int httpProxyPort; + protected volatile String httpProxyUsername; + protected volatile String httpProxyPassword; + + protected volatile String suiteTicket; + protected volatile long suiteTicketExpiresTime; + + + protected volatile File tmpDirFile; + + private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; + + @Override + public String getSuiteAccessToken() { + return this.suiteAccessToken; + } + + public void setSuiteAccessToken(String suiteAccessToken) { + this.suiteAccessToken = suiteAccessToken; + } + + @Override + public boolean isSuiteAccessTokenExpired() { + return System.currentTimeMillis() > this.expiresTime; + } + + @Override + public void expireSuiteAccessToken() { + this.expiresTime = 0; + } + + @Override + public synchronized void updateSuiteAccessToken(WxAccessToken suiteAccessToken) { + updateSuiteAccessToken(suiteAccessToken.getAccessToken(), suiteAccessToken.getExpiresIn()); + } + + @Override + public synchronized void updateSuiteAccessToken(String suiteAccessToken, int expiresInSeconds) { + this.suiteAccessToken = suiteAccessToken; + this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; + } + + @Override + public String getCorpId() { + return this.corpId; + } + + public void setCorpId(String corpId) { + this.corpId = corpId; + } + + @Override + public String getCorpSecret() { + return this.corpSecret; + } + + public void setCorpSecret(String corpSecret) { + this.corpSecret = corpSecret; + } + + @Override + public String getSuiteTicket() { + return this.suiteTicket; + } + + public void setSuiteTicket(String suiteTicket) { + this.suiteTicket = suiteTicket; + } + + public long getSuiteTicketExpiresTime() { + return this.suiteTicketExpiresTime; + } + + public void setSuiteTicketExpiresTime(long suiteTicketExpiresTime) { + this.suiteTicketExpiresTime = suiteTicketExpiresTime; + } + + @Override + public boolean isSuiteTicketExpired() { + return System.currentTimeMillis() > this.suiteTicketExpiresTime; + } + + @Override + public synchronized void updateSuiteTicket(String suiteTicket, int expiresInSeconds) { + this.suiteTicket = suiteTicket; + // 预留200秒的时间 + this.suiteTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; + } + + @Override + public void expireSuiteTicket() { + this.suiteTicketExpiresTime = 0; + } + + @Override + public String getSuiteId() { + return this.suiteId; + } + + public void setSuiteId(String corpId) { + this.suiteId = corpId; + } + + @Override + public String getSuiteSecret() { + return this.suiteSecret; + } + + public void setSuiteSecret(String corpSecret) { + this.suiteSecret = corpSecret; + } + + @Override + public String getToken() { + return this.token; + } + + public void setToken(String token) { + this.token = token; + } + + @Override + public long getExpiresTime() { + return this.expiresTime; + } + + public void setExpiresTime(long expiresTime) { + this.expiresTime = expiresTime; + } + + @Override + public String getAesKey() { + return this.aesKey; + } + + public void setAesKey(String aesKey) { + this.aesKey = aesKey; + } + + public void setOauth2redirectUri(String oauth2redirectUri) { + this.oauth2redirectUri = oauth2redirectUri; + } + + @Override + public String getHttpProxyHost() { + return this.httpProxyHost; + } + + public void setHttpProxyHost(String httpProxyHost) { + this.httpProxyHost = httpProxyHost; + } + + @Override + public int getHttpProxyPort() { + return this.httpProxyPort; + } + + public void setHttpProxyPort(int httpProxyPort) { + this.httpProxyPort = httpProxyPort; + } + + @Override + public String getHttpProxyUsername() { + return this.httpProxyUsername; + } + + public void setHttpProxyUsername(String httpProxyUsername) { + this.httpProxyUsername = httpProxyUsername; + } + + @Override + public String getHttpProxyPassword() { + return this.httpProxyPassword; + } + + public void setHttpProxyPassword(String httpProxyPassword) { + this.httpProxyPassword = httpProxyPassword; + } + + @Override + public String toString() { + return WxCpGsonBuilder.create().toJson(this); + } + + @Override + public File getTmpDirFile() { + return this.tmpDirFile; + } + + public void setTmpDirFile(File tmpDirFile) { + this.tmpDirFile = tmpDirFile; + } + + @Override + public ApacheHttpClientBuilder getApacheHttpClientBuilder() { + return this.apacheHttpClientBuilder; + } + + public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) { + this.apacheHttpClientBuilder = apacheHttpClientBuilder; + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpTpCryptUtil.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpTpCryptUtil.java new file mode 100644 index 0000000000..453d1700a9 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpTpCryptUtil.java @@ -0,0 +1,52 @@ +/** + * 对公众平台发送给公众账号的消息加解密示例代码. + * + * @copyright Copyright (c) 1998-2014 Tencent Inc. + *

+ * 针对org.apache.commons.codec.binary.Base64, + * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) + * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi + *

+ * 针对org.apache.commons.codec.binary.Base64, + * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) + * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi + */ + +// ------------------------------------------------------------------------ + +/** + * 针对org.apache.commons.codec.binary.Base64, + * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) + * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi + */ +package me.chanjar.weixin.cp.util.crypto; + +import org.apache.commons.codec.binary.Base64; + +import me.chanjar.weixin.common.util.crypto.WxCryptUtil; +import me.chanjar.weixin.cp.config.WxCpTpConfigStorage; + +public class WxCpTpCryptUtil extends WxCryptUtil { + + /** + * 构造函数 + * + * @param wxCpConfigStorage + */ + public WxCpTpCryptUtil(WxCpTpConfigStorage wxCpTpConfigStorage) { + /* + * @param token 公众平台上,开发者设置的token + * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey + * @param appidOrCorpid 公众平台corpId + */ + String encodingAesKey = wxCpTpConfigStorage.getAesKey(); + String token = wxCpTpConfigStorage.getToken(); + String corpId = wxCpTpConfigStorage.getCorpId(); + + this.token = token; + this.appidOrCorpid = corpId; + this.aesKey = Base64.decodeBase64(encodingAesKey + "="); + } + + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java index 5ef1503df1..3c6174c9d8 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java @@ -1,117 +1,135 @@ -package me.chanjar.weixin.cp.util.xml; - -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; - -import com.thoughtworks.xstream.XStream; -import me.chanjar.weixin.common.util.xml.XStreamInitializer; -import me.chanjar.weixin.cp.bean.WxCpXmlMessage; -import me.chanjar.weixin.cp.bean.WxCpXmlOutImageMessage; -import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; -import me.chanjar.weixin.cp.bean.WxCpXmlOutNewsMessage; -import me.chanjar.weixin.cp.bean.WxCpXmlOutTextMessage; -import me.chanjar.weixin.cp.bean.WxCpXmlOutVideoMessage; -import me.chanjar.weixin.cp.bean.WxCpXmlOutVoiceMessage; - -public class XStreamTransformer { - - protected static final Map CLASS_2_XSTREAM_INSTANCE = configXStreamInstance(); - - /** - * xml -> pojo - */ - @SuppressWarnings("unchecked") - public static T fromXml(Class clazz, String xml) { - T object = (T) CLASS_2_XSTREAM_INSTANCE.get(clazz).fromXML(xml); - return object; - } - - @SuppressWarnings("unchecked") - public static T fromXml(Class clazz, InputStream is) { - T object = (T) CLASS_2_XSTREAM_INSTANCE.get(clazz).fromXML(is); - return object; - } - - /** - * 注册扩展消息的解析器. - * - * @param clz 类型 - * @param xStream xml解析器 - */ - public static void register(Class clz, XStream xStream) { - CLASS_2_XSTREAM_INSTANCE.put(clz, xStream); - } - - /** - * pojo -> xml. - */ - public static String toXml(Class clazz, T object) { - return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object); - } - - private static Map configXStreamInstance() { - Map map = new HashMap<>(); - map.put(WxCpXmlMessage.class, configWxCpXmlMessage()); - map.put(WxCpXmlOutNewsMessage.class, configWxCpXmlOutNewsMessage()); - map.put(WxCpXmlOutTextMessage.class, configWxCpXmlOutTextMessage()); - map.put(WxCpXmlOutImageMessage.class, configWxCpXmlOutImageMessage()); - map.put(WxCpXmlOutVideoMessage.class, configWxCpXmlOutVideoMessage()); - map.put(WxCpXmlOutVoiceMessage.class, configWxCpXmlOutVoiceMessage()); - return map; - } - - private static XStream configWxCpXmlMessage() { - XStream xstream = XStreamInitializer.getInstance(); - - xstream.processAnnotations(WxCpXmlMessage.class); - xstream.processAnnotations(WxCpXmlMessage.ScanCodeInfo.class); - xstream.processAnnotations(WxCpXmlMessage.SendPicsInfo.class); - xstream.processAnnotations(WxCpXmlMessage.SendPicsInfo.Item.class); - xstream.processAnnotations(WxCpXmlMessage.SendLocationInfo.class); - return xstream; - } - - private static XStream configWxCpXmlOutImageMessage() { - XStream xstream = XStreamInitializer.getInstance(); - - xstream.processAnnotations(WxCpXmlOutMessage.class); - xstream.processAnnotations(WxCpXmlOutImageMessage.class); - return xstream; - } - - private static XStream configWxCpXmlOutNewsMessage() { - XStream xstream = XStreamInitializer.getInstance(); - - xstream.processAnnotations(WxCpXmlOutMessage.class); - xstream.processAnnotations(WxCpXmlOutNewsMessage.class); - xstream.processAnnotations(WxCpXmlOutNewsMessage.Item.class); - return xstream; - } - - private static XStream configWxCpXmlOutTextMessage() { - XStream xstream = XStreamInitializer.getInstance(); - - xstream.processAnnotations(WxCpXmlOutMessage.class); - xstream.processAnnotations(WxCpXmlOutTextMessage.class); - return xstream; - } - - private static XStream configWxCpXmlOutVideoMessage() { - XStream xstream = XStreamInitializer.getInstance(); - - xstream.processAnnotations(WxCpXmlOutMessage.class); - xstream.processAnnotations(WxCpXmlOutVideoMessage.class); - xstream.processAnnotations(WxCpXmlOutVideoMessage.Video.class); - return xstream; - } - - private static XStream configWxCpXmlOutVoiceMessage() { - XStream xstream = XStreamInitializer.getInstance(); - - xstream.processAnnotations(WxCpXmlOutMessage.class); - xstream.processAnnotations(WxCpXmlOutVoiceMessage.class); - return xstream; - } - -} +package me.chanjar.weixin.cp.util.xml; + +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +import com.thoughtworks.xstream.XStream; +import me.chanjar.weixin.common.util.xml.XStreamInitializer; +import me.chanjar.weixin.cp.bean.WxCpTpXmlMessage; +import me.chanjar.weixin.cp.bean.WxCpTpXmlPackage; +import me.chanjar.weixin.cp.bean.WxCpXmlMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutImageMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutNewsMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutTextMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutVideoMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutVoiceMessage; + +public class XStreamTransformer { + + protected static final Map CLASS_2_XSTREAM_INSTANCE = configXStreamInstance(); + + /** + * xml -> pojo + */ + @SuppressWarnings("unchecked") + public static T fromXml(Class clazz, String xml) { + T object = (T) CLASS_2_XSTREAM_INSTANCE.get(clazz).fromXML(xml); + return object; + } + + @SuppressWarnings("unchecked") + public static T fromXml(Class clazz, InputStream is) { + T object = (T) CLASS_2_XSTREAM_INSTANCE.get(clazz).fromXML(is); + return object; + } + + /** + * 注册扩展消息的解析器. + * + * @param clz 类型 + * @param xStream xml解析器 + */ + public static void register(Class clz, XStream xStream) { + CLASS_2_XSTREAM_INSTANCE.put(clz, xStream); + } + + /** + * pojo -> xml. + */ + public static String toXml(Class clazz, T object) { + return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object); + } + + private static Map configXStreamInstance() { + Map map = new HashMap<>(); + map.put(WxCpXmlMessage.class, configWxCpXmlMessage()); + map.put(WxCpXmlOutNewsMessage.class, configWxCpXmlOutNewsMessage()); + map.put(WxCpXmlOutTextMessage.class, configWxCpXmlOutTextMessage()); + map.put(WxCpXmlOutImageMessage.class, configWxCpXmlOutImageMessage()); + map.put(WxCpXmlOutVideoMessage.class, configWxCpXmlOutVideoMessage()); + map.put(WxCpXmlOutVoiceMessage.class, configWxCpXmlOutVoiceMessage()); + map.put(WxCpTpXmlPackage.class, configWxCpTpXmlPackage()); + map.put(WxCpTpXmlMessage.class, configWxCpTpXmlMessage()); + return map; + } + + private static XStream configWxCpXmlMessage() { + XStream xstream = XStreamInitializer.getInstance(); + + xstream.processAnnotations(WxCpXmlMessage.class); + xstream.processAnnotations(WxCpXmlMessage.ScanCodeInfo.class); + xstream.processAnnotations(WxCpXmlMessage.SendPicsInfo.class); + xstream.processAnnotations(WxCpXmlMessage.SendPicsInfo.Item.class); + xstream.processAnnotations(WxCpXmlMessage.SendLocationInfo.class); + return xstream; + } + + private static XStream configWxCpXmlOutImageMessage() { + XStream xstream = XStreamInitializer.getInstance(); + + xstream.processAnnotations(WxCpXmlOutMessage.class); + xstream.processAnnotations(WxCpXmlOutImageMessage.class); + return xstream; + } + + private static XStream configWxCpXmlOutNewsMessage() { + XStream xstream = XStreamInitializer.getInstance(); + + xstream.processAnnotations(WxCpXmlOutMessage.class); + xstream.processAnnotations(WxCpXmlOutNewsMessage.class); + xstream.processAnnotations(WxCpXmlOutNewsMessage.Item.class); + return xstream; + } + + private static XStream configWxCpXmlOutTextMessage() { + XStream xstream = XStreamInitializer.getInstance(); + + xstream.processAnnotations(WxCpXmlOutMessage.class); + xstream.processAnnotations(WxCpXmlOutTextMessage.class); + return xstream; + } + + private static XStream configWxCpXmlOutVideoMessage() { + XStream xstream = XStreamInitializer.getInstance(); + + xstream.processAnnotations(WxCpXmlOutMessage.class); + xstream.processAnnotations(WxCpXmlOutVideoMessage.class); + xstream.processAnnotations(WxCpXmlOutVideoMessage.Video.class); + return xstream; + } + + private static XStream configWxCpXmlOutVoiceMessage() { + XStream xstream = XStreamInitializer.getInstance(); + + xstream.processAnnotations(WxCpXmlOutMessage.class); + xstream.processAnnotations(WxCpXmlOutVoiceMessage.class); + return xstream; + } + + private static XStream configWxCpTpXmlPackage() { + XStream xstream = XStreamInitializer.getInstance(); + xstream.processAnnotations(WxCpTpXmlPackage.class); + + return xstream; + } + + private static XStream configWxCpTpXmlMessage() { + XStream xstream = XStreamInitializer.getInstance(); + xstream.processAnnotations(WxCpTpXmlMessage.class); + + return xstream; + } + +} From 19230472929a28380dde34d3e01cb95b9fecc602 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 26 May 2019 17:03:50 +0800 Subject: [PATCH 03/74] =?UTF-8?q?#1053=20=E4=BC=81=E4=B8=9A=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E6=A0=B9=E6=8D=AEcode=E8=8E=B7=E5=8F=96=E6=88=90?= =?UTF-8?q?=E5=91=98=E4=BF=A1=E6=81=AF=E6=8E=A5=E5=8F=A3=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E7=BB=93=E6=9E=9C=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/cp/api/WxCpOAuth2Service.java | 24 ++++++--- .../cp/api/impl/WxCpOAuth2ServiceImpl.java | 52 +++++++++---------- .../weixin/cp/bean/WxCpOauth2UserInfo.java | 28 ++++++++++ .../api/impl/WxCpOAuth2ServiceImplTest.java | 12 ++++- .../weixin/cp/demo/WxCpOAuth2Servlet.java | 5 +- 5 files changed, 85 insertions(+), 36 deletions(-) create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpOauth2UserInfo.java 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 5f3d6daa82..c6d9063fbb 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 @@ -1,20 +1,25 @@ package me.chanjar.weixin.cp.api; import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.cp.bean.WxCpOauth2UserInfo; import me.chanjar.weixin.cp.bean.WxCpUserDetail; /** *

- * OAuth2相关管理接口
+ * OAuth2相关管理接口.
  *  Created by BinaryWang on 2017/6/24.
  * 
* * @author Binary Wang */ public interface WxCpOAuth2Service { + String URL_GET_USER_INFO = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?code=%s&agentid=%d"; + String URL_GET_USER_DETAIL = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserdetail"; + String URL_OAUTH_2_AUTHORIZE = "https://open.weixin.qq.com/connect/oauth2/authorize"; + /** *
-   * 构造oauth2授权的url连接
+   * 构造oauth2授权的url连接.
    * 
* * @param state 状态码 @@ -24,7 +29,7 @@ public interface WxCpOAuth2Service { /** *
-   * 构造oauth2授权的url连接
+   * 构造oauth2授权的url连接.
    * 详情请见: http://qydev.weixin.qq.com/wiki/index.php?title=企业获取code
    * 
* @@ -57,16 +62,18 @@ public interface WxCpOAuth2Service { * * * @param code 微信oauth授权返回的代码 - * @return [userid, deviceid] + * @return WxCpOauth2UserInfo + * @throws WxErrorException 异常 * @see #getUserInfo(Integer, String) */ - String[] getUserInfo(String code) throws WxErrorException; + WxCpOauth2UserInfo getUserInfo(String code) throws WxErrorException; /** *
    * 根据code获取成员信息
    * http://qydev.weixin.qq.com/wiki/index.php?title=根据code获取成员信息
    * https://work.weixin.qq.com/api/doc#10028/根据code获取成员信息
+   * https://work.weixin.qq.com/api/doc#90000/90135/91023  获取访问用户身份
    * 因为企业号oauth2.0必须在应用设置里设置通过ICP备案的可信域名,所以无法测试,因此这个方法很可能是坏的。
    *
    * 注意: 这个方法不使用WxCpConfigStorage里的agentId,需要开发人员自己给出
@@ -74,10 +81,11 @@ public interface WxCpOAuth2Service {
    *
    * @param agentId 企业号应用的id
    * @param code    通过成员授权获取到的code,最大为512字节。每次成员授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。
-   * @return [UserId, DeviceId, OpenId, user_ticket, expires_in]
+   * @return WxCpOauth2UserInfo
+   * @throws WxErrorException 异常
    * @see #getUserInfo(String)
    */
-  String[] getUserInfo(Integer agentId, String code) throws WxErrorException;
+  WxCpOauth2UserInfo getUserInfo(Integer agentId, String code) throws WxErrorException;
 
   /**
    * 
@@ -92,6 +100,8 @@ public interface WxCpOAuth2Service {
    * 
* * @param userTicket 成员票据 + * @return WxCpUserDetail + * @throws WxErrorException 异常 */ WxCpUserDetail getUserDetail(String userTicket) throws WxErrorException; } 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 3507de0769..6ff91fc35a 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 @@ -3,30 +3,31 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import lombok.AllArgsConstructor; 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; import me.chanjar.weixin.cp.api.WxCpOAuth2Service; import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.WxCpOauth2UserInfo; import me.chanjar.weixin.cp.bean.WxCpUserDetail; import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; +import static me.chanjar.weixin.common.api.WxConsts.OAuth2Scope.SNSAPI_PRIVATEINFO; +import static me.chanjar.weixin.common.api.WxConsts.OAuth2Scope.SNSAPI_USERINFO; + /** *
- *
+ * oauth2相关接口实现类.
  * Created by Binary Wang on 2017-6-25.
- * @author Binary Wang
- *
- * @author Binary Wang
  * 
+ * + * @author Binary Wang */ +@AllArgsConstructor public class WxCpOAuth2ServiceImpl implements WxCpOAuth2Service { - private WxCpService mainService; - - public WxCpOAuth2ServiceImpl(WxCpService mainService) { - this.mainService = mainService; - } + private final WxCpService mainService; @Override public String buildAuthorizationUrl(String state) { @@ -43,50 +44,49 @@ public String buildAuthorizationUrl(String redirectUri, String state) { @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()); + StringBuilder url = new StringBuilder(WxCpOAuth2Service.URL_OAUTH_2_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)) { + if (SNSAPI_PRIVATEINFO.equals(scope) || SNSAPI_USERINFO.equals(scope)) { url.append("&agentid=").append(this.mainService.getWxCpConfigStorage().getAgentId()); } if (state != null) { url.append("&state=").append(state); } + url.append("#wechat_redirect"); return url.toString(); } @Override - public String[] getUserInfo(String code) throws WxErrorException { + public WxCpOauth2UserInfo getUserInfo(String code) throws WxErrorException { return this.getUserInfo(this.mainService.getWxCpConfigStorage().getAgentId(), code); } @Override - public String[] getUserInfo(Integer agentId, String code) throws WxErrorException { - String url = String.format("https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?code=%s&agentid=%d", - code, agentId); - String responseText = this.mainService.get(url, null); + public WxCpOauth2UserInfo getUserInfo(Integer agentId, String code) throws WxErrorException { + String responseText = this.mainService.get(String.format(WxCpOAuth2Service.URL_GET_USER_INFO, code, agentId), null); JsonElement je = new JsonParser().parse(responseText); JsonObject jo = je.getAsJsonObject(); - return new String[]{GsonHelper.getString(jo, "UserId"), - GsonHelper.getString(jo, "DeviceId"), - GsonHelper.getString(jo, "OpenId"), - GsonHelper.getString(jo, "user_ticket"), - GsonHelper.getString(jo, "expires_in") - }; + + return WxCpOauth2UserInfo.builder() + .userId(GsonHelper.getString(jo, "UserId")) + .deviceId(GsonHelper.getString(jo, "DeviceId")) + .openId(GsonHelper.getString(jo, "OpenId")) + .userTicket(GsonHelper.getString(jo, "user_ticket")) + .expiresIn(GsonHelper.getString(jo, "expires_in")) + .build(); } @Override public WxCpUserDetail getUserDetail(String userTicket) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserdetail"; JsonObject param = new JsonObject(); param.addProperty("user_ticket", userTicket); - String responseText = this.mainService.post(url, param.toString()); + String responseText = this.mainService.post(WxCpOAuth2Service.URL_GET_USER_DETAIL, param.toString()); return WxCpGsonBuilder.create().fromJson(responseText, WxCpUserDetail.class); } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpOauth2UserInfo.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpOauth2UserInfo.java new file mode 100644 index 0000000000..9122f18d3a --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpOauth2UserInfo.java @@ -0,0 +1,28 @@ +package me.chanjar.weixin.cp.bean; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + *
+ *  用oauth2获取用户信息的结果类
+ *  Created by BinaryWang on 2019/5/26.
+ * 
+ * + * @author Binary Wang + */ +@Data +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class WxCpOauth2UserInfo { + private String openId; + private String deviceId; + private String userId; + private String userTicket; + private String expiresIn; +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImplTest.java index 21801e4b42..4df8756334 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImplTest.java @@ -4,10 +4,13 @@ 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.WxCpOauth2UserInfo; import me.chanjar.weixin.cp.bean.WxCpUserDetail; import org.testng.annotations.Guice; import org.testng.annotations.Test; +import static org.assertj.core.api.Assertions.assertThat; + /** *
  *  Created by BinaryWang on 2018/4/22.
@@ -28,6 +31,13 @@ public void testGetUserDetail() throws WxErrorException {
 
   @Test
   public void testGetUserInfo() throws WxErrorException {
-    this.wxService.getOauth2Service().getUserInfo("abc");
+    final WxCpOauth2UserInfo result = this.wxService.getOauth2Service().getUserInfo("abc");
+    assertThat(result).isNotNull();
+    System.out.println(result);
   }
+
+  @Test
+  public void testBuildAuthorizationUrl() {
+  }
+
 }
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpOAuth2Servlet.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpOAuth2Servlet.java
index d652884b64..14d933da8a 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpOAuth2Servlet.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpOAuth2Servlet.java
@@ -2,6 +2,7 @@
 
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.cp.api.WxCpService;
+import me.chanjar.weixin.cp.bean.WxCpOauth2UserInfo;
 
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
@@ -30,9 +31,9 @@ protected void service(HttpServletRequest request, HttpServletResponse response)
       response.getWriter().println("

code

"); response.getWriter().println(code); - String[] res = this.wxCpService.getOauth2Service().getUserInfo(code); + WxCpOauth2UserInfo res = this.wxCpService.getOauth2Service().getUserInfo(code); response.getWriter().println("

result

"); - response.getWriter().println(Arrays.toString(res)); + response.getWriter().println(res); } catch (WxErrorException e) { e.printStackTrace(); } From e1b623906b864cdbd7091cb725504e7f6d57afe5 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 26 May 2019 17:09:28 +0800 Subject: [PATCH 04/74] =?UTF-8?q?=E5=8F=91=E5=B8=833.4.1.B=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- starters/wx-java-mp-starter/pom.xml | 2 +- starters/wx-java-pay-starter/pom.xml | 2 +- weixin-java-common/pom.xml | 2 +- weixin-java-cp/pom.xml | 2 +- weixin-java-miniapp/pom.xml | 2 +- weixin-java-mp/pom.xml | 2 +- weixin-java-open/pom.xml | 2 +- weixin-java-pay/pom.xml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index 49ccee6520..07631b61b7 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 com.github.binarywang wx-java - 3.4.0 + 3.4.1.B pom WxJava - Weixin/Wechat Java SDK 微信开发Java SDK diff --git a/starters/wx-java-mp-starter/pom.xml b/starters/wx-java-mp-starter/pom.xml index 639662b8fe..2c276e94e2 100644 --- a/starters/wx-java-mp-starter/pom.xml +++ b/starters/wx-java-mp-starter/pom.xml @@ -6,7 +6,7 @@ com.github.binarywang wx-java - 3.4.0 + 3.4.1.B ../../ diff --git a/starters/wx-java-pay-starter/pom.xml b/starters/wx-java-pay-starter/pom.xml index eba398b454..4201da5b76 100644 --- a/starters/wx-java-pay-starter/pom.xml +++ b/starters/wx-java-pay-starter/pom.xml @@ -5,7 +5,7 @@ wx-java com.github.binarywang - 3.4.0 + 3.4.1.B ../../ 4.0.0 diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index 7e5f54fefc..2ddba54d34 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -6,7 +6,7 @@ com.github.binarywang wx-java - 3.4.0 + 3.4.1.B weixin-java-common diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index 09208eb329..8de47acac2 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.4.0 + 3.4.1.B weixin-java-cp diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml index de3c9f50df..3c7b511468 100644 --- a/weixin-java-miniapp/pom.xml +++ b/weixin-java-miniapp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.4.0 + 3.4.1.B weixin-java-miniapp diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index ed8c7e75de..8bd9841711 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.4.0 + 3.4.1.B weixin-java-mp diff --git a/weixin-java-open/pom.xml b/weixin-java-open/pom.xml index a624a38c7f..549aa5b4fa 100644 --- a/weixin-java-open/pom.xml +++ b/weixin-java-open/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.4.0 + 3.4.1.B weixin-java-open diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index a6130d13ee..115b07e286 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -5,7 +5,7 @@ com.github.binarywang wx-java - 3.4.0 + 3.4.1.B 4.0.0 From 3465d538803eee981dabcd7e3bd51f9c0b1474e9 Mon Sep 17 00:00:00 2001 From: Xiaoyu Guo Date: Tue, 28 May 2019 12:41:09 +0800 Subject: [PATCH 05/74] =?UTF-8?q?#1058=20=E5=85=AC=E4=BC=97=E5=8F=B7?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E5=8A=A0=E5=85=A5=E8=AE=BE=E5=A4=87=E7=BB=91?= =?UTF-8?q?=E5=AE=9A=E8=A7=A3=E7=BB=91=E6=B6=88=E6=81=AF=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://iot.weixin.qq.com/wiki/new/index.html?page=3-4-2 --- .../mp/bean/message/WxMpXmlMessage.java | 8 ++++ .../bean/message/WxMpXmlOutDeviceMessage.java | 36 ++++++++++++++ .../mp/bean/message/WxMpXmlOutMessage.java | 7 +++ .../mp/builder/outxml/DeviceBuilder.java | 48 +++++++++++++++++++ 4 files changed, 99 insertions(+) create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutDeviceMessage.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/DeviceBuilder.java 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 368f70e383..ba6fd227be 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 @@ -527,6 +527,14 @@ public class WxMpXmlMessage implements Serializable { @XStreamAlias("DeviceID") @XStreamConverter(value = XStreamCDataConverter.class) private String deviceId; + + /** + * 微信客户端生成的session id,用于request和response对应, + * 因此响应中该字段第三方需要原封不变的带回 + */ + @XStreamAlias("SessionID") + @XStreamConverter(value = XStreamCDataConverter.class) + private String sessionId; /** * 微信用户账号的OpenID. diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutDeviceMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutDeviceMessage.java new file mode 100644 index 0000000000..b32935a106 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutDeviceMessage.java @@ -0,0 +1,36 @@ +package me.chanjar.weixin.mp.bean.message; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamConverter; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; + +@XStreamAlias("xml") +@Data +@EqualsAndHashCode(callSuper = true) +public class WxMpXmlOutDeviceMessage extends WxMpXmlOutMessage { + private static final long serialVersionUID = -3093843149649157587L; + + @XStreamAlias("DeviceType") + @XStreamConverter(value = XStreamCDataConverter.class) + private String deviceType; + + @XStreamAlias("DeviceID") + @XStreamConverter(value = XStreamCDataConverter.class) + private String deviceId; + + @XStreamAlias("Content") + @XStreamConverter(value = XStreamCDataConverter.class) + private String content; + + @XStreamAlias("SessionID") + @XStreamConverter(value = XStreamCDataConverter.class) + private String sessionId; + + public WxMpXmlOutDeviceMessage() { + this.msgType = WxConsts.XmlMsgType.DEVICE_TEXT; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutMessage.java index b1940fc487..74b053f17d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutMessage.java @@ -79,6 +79,13 @@ public static NewsBuilder NEWS() { public static TransferCustomerServiceBuilder TRANSFER_CUSTOMER_SERVICE() { return new TransferCustomerServiceBuilder(); } + + /** + * 获得设备消息builder + */ + public static DeviceBuilder DEVICE() { + return new DeviceBuilder(); + } @SuppressWarnings("unchecked") public String toXml() { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/DeviceBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/DeviceBuilder.java new file mode 100644 index 0000000000..664c2e3a02 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/outxml/DeviceBuilder.java @@ -0,0 +1,48 @@ +package me.chanjar.weixin.mp.builder.outxml; + +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutDeviceMessage; + +/** + * 设备消息 Builder + * @author biggates + * @see https://iot.weixin.qq.com/wiki/new/index.html?page=3-4-2 + */ +public final class DeviceBuilder extends BaseBuilder { + + private String deviceId; + private String deviceType; + private String content; + private String sessionId; + + public DeviceBuilder deviceType(String deviceType) { + this.deviceType = deviceType; + return this; + } + + public DeviceBuilder deviceId(String deviceId) { + this.deviceId = deviceId; + return this; + } + + public DeviceBuilder content(String content) { + this.content = content; + return this; + } + + public DeviceBuilder sessionId(String sessionId) { + this.sessionId = sessionId; + return this; + } + + @Override + public WxMpXmlOutDeviceMessage build() { + WxMpXmlOutDeviceMessage m = new WxMpXmlOutDeviceMessage(); + setCommon(m); + m.setDeviceId(this.deviceId); + m.setDeviceType(this.deviceType); + m.setContent(this.content); + m.setSessionId(this.sessionId); + return m; + } + +} From f67333a06ad464fb27c162b328d58ca5e037ea3a Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 2 Jun 2019 12:19:18 +0800 Subject: [PATCH 06/74] =?UTF-8?q?=E8=A7=84=E8=8C=83=E5=8C=96=E5=B9=B6?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/cp/api/WxCpAgentService.java | 3 + .../weixin/cp/api/WxCpChatService.java | 36 +- .../weixin/cp/api/WxCpDepartmentService.java | 4 + .../weixin/cp/api/WxCpMenuService.java | 4 + .../chanjar/weixin/cp/api/WxCpOAService.java | 66 ---- .../chanjar/weixin/cp/api/WxCpOaService.java | 68 ++++ .../me/chanjar/weixin/cp/api/WxCpService.java | 5 +- .../chanjar/weixin/cp/api/WxCpTagService.java | 25 +- .../weixin/cp/api/WxCpTaskCardService.java | 2 + .../chanjar/weixin/cp/api/WxCpTpService.java | 342 +++++++++--------- .../weixin/cp/api/WxCpUserService.java | 13 + .../cp/api/impl/BaseWxCpServiceImpl.java | 4 +- .../cp/api/impl/WxCpAgentServiceImpl.java | 9 +- .../cp/api/impl/WxCpChatServiceImpl.java | 2 +- .../api/impl/WxCpDepartmentServiceImpl.java | 10 +- .../cp/api/impl/WxCpMenuServiceImpl.java | 12 +- ...erviceImpl.java => WxCpOaServiceImpl.java} | 48 +-- .../impl/WxCpServiceApacheHttpClientImpl.java | 13 +- .../cp/api/impl/WxCpServiceJoddHttpImpl.java | 10 +- .../cp/api/impl/WxCpServiceOkHttpImpl.java | 51 +-- .../cp/api/impl/WxCpTagServiceImpl.java | 44 +-- .../cp/api/impl/WxCpTaskCardServiceImpl.java | 3 +- .../WxCpTpServiceApacheHttpClientImpl.java | 228 ++++++------ .../cp/api/impl/WxCpUserServiceImpl.java | 43 +-- .../weixin/cp/bean/WxCpTagGetResult.java | 6 +- .../cp/api/impl/WxCpAgentServiceImplTest.java | 3 +- ...plTest.java => WxCpOaServiceImplTest.java} | 2 +- .../cp/api/impl/WxCpTagServiceImplTest.java | 9 +- .../wxpay/bean/request/BaseWxPayRequest.java | 2 + .../request/WxPayUnifiedOrderRequest.java | 2 + 30 files changed, 534 insertions(+), 535 deletions(-) delete mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOAService.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaService.java rename weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/{WxCpOAServiceImpl.java => WxCpOaServiceImpl.java} (71%) rename weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/{WxCpOAServiceImplTest.java => WxCpOaServiceImplTest.java} (97%) 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 feea8acbd1..30214a478f 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 @@ -15,6 +15,9 @@ * @author huansinho */ public interface WxCpAgentService { + String GET_AGENT = "https://qyapi.weixin.qq.com/cgi-bin/agent/get?agentid=%d"; + String AGENT_SET = "https://qyapi.weixin.qq.com/cgi-bin/agent/set"; + String AGENT_LIST = "https://qyapi.weixin.qq.com/cgi-bin/agent/list"; /** *
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpChatService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpChatService.java
index 95f747e356..bbfc0fdd48 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpChatService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpChatService.java
@@ -1,11 +1,11 @@
 package me.chanjar.weixin.cp.api;
 
-import java.util.List;
-
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.cp.bean.WxCpAppChatMessage;
 import me.chanjar.weixin.cp.bean.WxCpChat;
 
+import java.util.List;
+
 /**
  * 群聊服务.
  *
@@ -15,6 +15,10 @@ public interface WxCpChatService {
   String APPCHAT_CREATE = "https://qyapi.weixin.qq.com/cgi-bin/appchat/create";
   String APPCHAT_UPDATE = "https://qyapi.weixin.qq.com/cgi-bin/appchat/update";
   String APPCHAT_GET_CHATID = "https://qyapi.weixin.qq.com/cgi-bin/appchat/get?chatid=";
+  String APPCHAT_SEND = "https://qyapi.weixin.qq.com/cgi-bin/appchat/send";
+
+  @Deprecated
+  String chatCreate(String name, String owner, List users, String chatId) throws WxErrorException;
 
   /**
    * 创建群聊会话,注意:刚创建的群,如果没有下发消息,在企业微信不会出现该群.
@@ -24,15 +28,13 @@ public interface WxCpChatService {
    * @param users  群成员id列表。至少2人,至多500人
    * @param chatId 群聊的唯一标志,不能与已有的群重复;字符串类型,最长32个字符。只允许字符0-9及字母a-zA-Z。如果不填,系统会随机生成群id
    * @return 创建的群聊会话chatId
-   * @throws WxErrorException 发生异常
-   */
-  String chatCreate(String name, String owner, List users, String chatId) throws WxErrorException;
-
-  /**
-   * chatCreate 同名方法
+   * @throws WxErrorException 异常
    */
   String create(String name, String owner, List users, String chatId) throws WxErrorException;
 
+  @Deprecated
+  void chatUpdate(String chatId, String name, String owner, List usersToAdd, List usersToDelete) throws WxErrorException;
+
   /**
    * 修改群聊会话.
    *
@@ -41,26 +43,19 @@ public interface WxCpChatService {
    * @param owner         新群主的id。若不需更新,请忽略此参数(null or empty)
    * @param usersToAdd    添加成员的id列表,若不需要更新,则传递空对象或者空集合
    * @param usersToDelete 踢出成员的id列表,若不需要更新,则传递空对象或者空集合
-   * @throws WxErrorException 发生异常
-   */
-  void chatUpdate(String chatId, String name, String owner, List usersToAdd, List usersToDelete) throws WxErrorException;
-
-  /**
-   * chatUpdate 同名方法
+   * @throws WxErrorException 异常
    */
   void update(String chatId, String name, String owner, List usersToAdd, List usersToDelete) throws WxErrorException;
 
+  @Deprecated
+  WxCpChat chatGet(String chatId) throws WxErrorException;
+
   /**
    * 获取群聊会话.
    *
    * @param chatId 群聊编号
    * @return 群聊会话
-   * @throws WxErrorException 发生异常
-   */
-  WxCpChat chatGet(String chatId) throws WxErrorException;
-
-  /**
-   * chatGet 同名方法
+   * @throws WxErrorException 异常
    */
   WxCpChat get(String chatId) throws WxErrorException;
 
@@ -71,6 +66,7 @@ public interface WxCpChatService {
    * 文档地址:https://work.weixin.qq.com/api/doc#90000/90135/90248
    *
    * @param message 要发送的消息内容对象
+   * @throws WxErrorException 异常
    */
   void sendMsg(WxCpAppChatMessage message) throws WxErrorException;
 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java
index 8af1d3041a..3f80d693ad 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java
@@ -14,6 +14,10 @@
  * @author Binary Wang
  */
 public interface WxCpDepartmentService {
+  String DEPARTMENT_CREATE = "https://qyapi.weixin.qq.com/cgi-bin/department/create";
+  String DEPARTMENT_UPDATE = "https://qyapi.weixin.qq.com/cgi-bin/department/update";
+  String DEPARTMENT_DELETE = "https://qyapi.weixin.qq.com/cgi-bin/department/delete?id=%d";
+  String DEPARTMENT_LIST = "https://qyapi.weixin.qq.com/cgi-bin/department/list";
 
   /**
    * 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java
index 068c037a48..be7b4b7e55 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java
@@ -12,6 +12,10 @@
  * @author Binary Wang
  */
 public interface WxCpMenuService {
+  String MENU_CREATE = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?agentid=%d";
+  String MENU_DELETE = "https://qyapi.weixin.qq.com/cgi-bin/menu/delete?agentid=%d";
+  String MENU_GET = "https://qyapi.weixin.qq.com/cgi-bin/menu/get?agentid=%d";
+
   /**
    * 
    * 自定义菜单创建接口
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOAService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOAService.java
deleted file mode 100644
index e8cf874eb6..0000000000
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOAService.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package me.chanjar.weixin.cp.api;
-
-import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.cp.bean.WxCpApprovalDataResult;
-import me.chanjar.weixin.cp.bean.WxCpCheckinData;
-import me.chanjar.weixin.cp.bean.WxCpCheckinOption;
-import me.chanjar.weixin.cp.bean.WxCpDialRecord;
-
-import java.util.Date;
-import java.util.List;
-
-/**
- * @author Element
- * @Package me.chanjar.weixin.cp.api
- * @date 2019-04-06 10:52
- * @Description: 
- *     企业微信OA相关接口
- *
- * 
- */ -public interface WxCpOAService { - - /** - *
-   *     获取打卡数据
-   *     API doc : https://work.weixin.qq.com/api/doc#90000/90135/90262
-   * 
- * - * @param openCheckinDataType 打卡类型。1:上下班打卡;2:外出打卡;3:全部打卡 - * @param starttime 获取打卡记录的开始时间 - * @param endtime 获取打卡记录的结束时间 - * @param userIdList 需要获取打卡记录的用户列表 - */ - List getCheckinData(Integer openCheckinDataType, Date starttime, Date endtime, List userIdList) throws WxErrorException; - - /** - *
-   *     获取打卡规则
-   *     API doc : https://work.weixin.qq.com/api/doc#90000/90135/90263
-   * 
- * - * @param datetime 需要获取规则的当天日期 - * @param userIdList 需要获取打卡规则的用户列表 - * @return - * @throws WxErrorException - */ - List getCheckinOption(Date datetime, List userIdList) throws WxErrorException; - - /** - *
-   *     获取审批数据
-   *     通过本接口来获取公司一段时间内的审批记录。一次拉取调用最多拉取10000个审批记录,可以通过多次拉取的方式来满足需求,但调用频率不可超过600次/分。
-   *     API doc : https://work.weixin.qq.com/api/doc#90000/90135/91530
-   * 
- * - * @param starttime 获取审批记录的开始时间 - * @param endtime 获取审批记录的结束时间 - * @param nextSpnum 第一个拉取的审批单号,不填从该时间段的第一个审批单拉取 - * @return - * @throws WxErrorException - */ - WxCpApprovalDataResult getApprovalData(Date starttime, Date endtime, Long nextSpnum) throws WxErrorException; - - List getDialRecord(Date starttime, Date endtime, Integer offset, Integer limit) throws WxErrorException; - -} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaService.java new file mode 100644 index 0000000000..26922c0eee --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaService.java @@ -0,0 +1,68 @@ +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.cp.bean.WxCpApprovalDataResult; +import me.chanjar.weixin.cp.bean.WxCpCheckinData; +import me.chanjar.weixin.cp.bean.WxCpCheckinOption; +import me.chanjar.weixin.cp.bean.WxCpDialRecord; + +import java.util.Date; +import java.util.List; + +/** + * 企业微信OA相关接口. + * + * @author Element + * @date 2019-04-06 10:52 + */ +public interface WxCpOaService { + String GET_CHECKIN_DATA = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckindata"; + String GET_CHECKIN_OPTION = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckinoption"; + String GET_APPROVAL_DATA = "https://qyapi.weixin.qq.com/cgi-bin/corp/getapprovaldata"; + String GET_DIAL_RECORD = "https://qyapi.weixin.qq.com/cgi-bin/dial/get_dial_record"; + + /** + *
+   *  获取打卡数据
+   *  API doc : https://work.weixin.qq.com/api/doc#90000/90135/90262
+   * 
+ * + * @param openCheckinDataType 打卡类型。1:上下班打卡;2:外出打卡;3:全部打卡 + * @param startTime 获取打卡记录的开始时间 + * @param endTime 获取打卡记录的结束时间 + * @param userIdList 需要获取打卡记录的用户列表 + * @return 打卡数据列表 + * @throws WxErrorException 异常 + */ + List getCheckinData(Integer openCheckinDataType, Date startTime, Date endTime, List userIdList) throws WxErrorException; + + /** + *
+   *   获取打卡规则
+   *   API doc : https://work.weixin.qq.com/api/doc#90000/90135/90263
+   * 
+ * + * @param datetime 需要获取规则的当天日期 + * @param userIdList 需要获取打卡规则的用户列表 + * @return 打卡规则列表 + * @throws WxErrorException 异常 + */ + List getCheckinOption(Date datetime, List userIdList) throws WxErrorException; + + /** + *
+   *   获取审批数据
+   *   通过本接口来获取公司一段时间内的审批记录。一次拉取调用最多拉取10000个审批记录,可以通过多次拉取的方式来满足需求,但调用频率不可超过600次/分。
+   *   API doc : https://work.weixin.qq.com/api/doc#90000/90135/91530
+   * 
+ * + * @param startTime 获取审批记录的开始时间 + * @param endTime 获取审批记录的结束时间 + * @param nextSpnum 第一个拉取的审批单号,不填从该时间段的第一个审批单拉取 + * @throws WxErrorException 异常 + */ + WxCpApprovalDataResult getApprovalData(Date startTime, Date endTime, Long nextSpnum) throws WxErrorException; + + List getDialRecord(Date startTime, Date endTime, Integer offset, Integer limit) throws WxErrorException; + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java index 364723db87..13d2e9dc4a 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java @@ -13,7 +13,7 @@ import me.chanjar.weixin.cp.config.WxCpConfigStorage; /** - * 微信API的Service + * 微信API的Service. * @author chanjaster */ public interface WxCpService { @@ -25,6 +25,7 @@ public interface WxCpService { String BATCH_REPLACE_USER = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceuser"; String BATCH_GET_RESULT = "https://qyapi.weixin.qq.com/cgi-bin/batch/getresult?jobid="; String JSCODE_TO_SESSION_URL = "https://qyapi.weixin.qq.com/cgi-bin/miniprogram/jscode2session"; + String GET_TOKEN = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?&corpid=%s&corpsecret=%s"; /** *
@@ -310,7 +311,7 @@ public interface WxCpService {
 
   WxCpAgentService getAgentService();
 
-  WxCpOAService getOAService();
+  WxCpOaService getOAService();
 
   /**
    * http请求对象
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java
index 9624f9e409..a570a80b10 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java
@@ -17,6 +17,14 @@
  * @author Binary Wang
  */
 public interface WxCpTagService {
+  String TAG_CREATE = "https://qyapi.weixin.qq.com/cgi-bin/tag/create";
+  String TAG_UPDATE = "https://qyapi.weixin.qq.com/cgi-bin/tag/update";
+  String TAG_DELETE = "https://qyapi.weixin.qq.com/cgi-bin/tag/delete?tagid=%s";
+  String TAG_LIST = "https://qyapi.weixin.qq.com/cgi-bin/tag/list";
+  String TAG_GET = "https://qyapi.weixin.qq.com/cgi-bin/tag/get?tagid=%s";
+  String TAG_ADDTAGUSERS = "https://qyapi.weixin.qq.com/cgi-bin/tag/addtagusers";
+  String TAG_DELTAGUSERS = "https://qyapi.weixin.qq.com/cgi-bin/tag/deltagusers";
+
   /**
    * 创建标签.
    *
@@ -51,6 +59,14 @@ public interface WxCpTagService {
    */
   List listUsersByTagId(String tagId) throws WxErrorException;
 
+  /**
+   * 获取标签成员.
+   * 对应: http://qydev.weixin.qq.com/wiki/index.php?title=管理标签 中的get接口
+   *
+   * @param tagId 标签id
+   */
+  WxCpTagGetResult get(String tagId) throws WxErrorException;
+
   /**
    * 增加标签成员.
    *
@@ -69,13 +85,4 @@ public interface WxCpTagService {
    */
   WxCpTagAddOrRemoveUsersResult removeUsersFromTag(String tagId, List userIds, List partyIds) throws WxErrorException;
 
-
-  /**
-   * 获取标签成员.
-   * 对应: http://qydev.weixin.qq.com/wiki/index.php?title=管理标签 中的get接口
-   *
-   * @param tagId 标签id
-   */
-  WxCpTagGetResult get(String tagId) throws WxErrorException;
-
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTaskCardService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTaskCardService.java
index 038c2dd3bf..1e1077014f 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTaskCardService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTaskCardService.java
@@ -14,6 +14,8 @@
  * @date 2019-05-16
  */
 public interface WxCpTaskCardService {
+  String MESSAGE_UPDATE_TASKCARD = "https://qyapi.weixin.qq.com/cgi-bin/message/update_taskcard";
+
   /**
    * 
    * 更新任务卡片消息状态
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java
index 741d27de58..6e0d63fb2c 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java
@@ -1,169 +1,173 @@
-package me.chanjar.weixin.cp.api;
-
-import me.chanjar.weixin.common.bean.WxAccessToken;
-import me.chanjar.weixin.common.error.WxErrorException;
-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.cp.bean.WxCpMaJsCode2SessionResult;
-import me.chanjar.weixin.cp.bean.WxCpTpCorp;
-import me.chanjar.weixin.cp.config.WxCpConfigStorage;
-import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
-
-/**
- * 微信第三方应用API的Service
- * @author zhenjun cai
- */
-public interface WxCpTpService {
-  String JSCODE_TO_SESSION_URL = "https://qyapi.weixin.qq.com/cgi-bin/service/miniprogram/jscode2session";
-  String GET_CORP_TOKEN = "https://qyapi.weixin.qq.com/cgi-bin/service/get_corp_token";
-  String GET_PERMANENT_CODE = "https://qyapi.weixin.qq.com/cgi-bin/service/get_permanent_code";
-  /**
-   * 
-   * 验证推送过来的消息的正确性
-   * 详情请见: https://work.weixin.qq.com/api/doc#90000/90139/90968/消息体签名校验
-   * 
- * - * @param msgSignature 消息签名 - * @param timestamp 时间戳 - * @param nonce 随机数 - * @param data 微信传输过来的数据,有可能是echoStr,有可能是xml消息 - */ - boolean checkSignature(String msgSignature, String timestamp, String nonce, String data); - - /** - * 获取suite_access_token, 不强制刷新suite_access_token - * - * @see #getSuiteAccessToken(boolean) - */ - String getSuiteAccessToken() throws WxErrorException; - - /** - *
-   * 获取suite_access_token,本方法线程安全
-   * 且在多线程同时刷新时只刷新一次,避免超出2000次/日的调用次数上限
-   * 另:本service的所有方法都会在suite_access_token过期是调用此方法
-   * 程序员在非必要情况下尽量不要主动调用此方法
-   * 详情请见: https://work.weixin.qq.com/api/doc#90001/90143/90600
-   * 
- * - * @param forceRefresh 强制刷新 - */ - String getSuiteAccessToken(boolean forceRefresh) throws WxErrorException; - - /** - * 获得suite_ticket,不强制刷新suite_ticket - * - * @see #getSuiteTicket(boolean) - */ - String getSuiteTicket() throws WxErrorException; - - /** - *
-   * 获得suite_ticket
-   * 由于suite_ticket是微信服务器定时推送(每10分钟),不能主动获取,如果碰到过期只能抛异常
-   *
-   * 详情请见:https://work.weixin.qq.com/api/doc#90001/90143/90628
-   * 
- * - * @param forceRefresh 强制刷新 - */ - String getSuiteTicket(boolean forceRefresh) throws WxErrorException; - - /** - * 小程序登录凭证校验 - * - * @param jsCode 登录时获取的 code - */ - WxCpMaJsCode2SessionResult jsCode2Session(String jsCode) throws WxErrorException; - - /** - * 获取企业凭证 - * @param authCorpid 授权方corpid - * @param permanentCode 永久授权码,通过get_permanent_code获取 - */ - WxAccessToken getCorpToken(String authCorpid, String permanentCode) throws WxErrorException; - - /** - * 获取企业永久授权码 - * @param authCode - * @return - */ - WxCpTpCorp getPermanentCode(String authCode) throws WxErrorException; - - /** - * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求 - * - * @param url 接口地址 - * @param queryParam 请求参数 - */ - String get(String url, String queryParam) throws WxErrorException; - - /** - * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求 - * - * @param url 接口地址 - * @param postData 请求body字符串 - */ - String post(String url, String postData) throws WxErrorException; - - /** - *
-   * Service没有实现某个API的时候,可以用这个,
-   * 比{@link #get}和{@link #post}方法更灵活,可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。
-   * 可以参考,{@link MediaUploadRequestExecutor}的实现方法
-   * 
- * - * @param executor 执行器 - * @param uri 请求地址 - * @param data 参数 - * @param 请求值类型 - * @param 返回值类型 - */ - T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; - - /** - *
-   * 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试
-   * 默认:1000ms
-   * 
- * - * @param retrySleepMillis 重试休息时间 - */ - void setRetrySleepMillis(int retrySleepMillis); - - /** - *
-   * 设置当微信系统响应系统繁忙时,最大重试次数
-   * 默认:5次
-   * 
- * - * @param maxRetryTimes 最大重试次数 - */ - void setMaxRetryTimes(int maxRetryTimes); - - /** - * 初始化http请求对象 - */ - void initHttp(); - - /** - * 获取WxMpConfigStorage 对象 - * - * @return WxMpConfigStorage - */ - WxCpTpConfigStorage getWxCpTpConfigStorage(); - - /** - * 注入 {@link WxCpTpConfigStorage} 的实现 - * - * @param wxConfigProvider 配置对象 - */ - void setWxCpTpConfigStorage(WxCpTpConfigStorage wxConfigProvider); - - /** - * http请求对象 - */ - RequestHttp getRequestHttp(); - -} +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.error.WxErrorException; +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.cp.bean.WxCpMaJsCode2SessionResult; +import me.chanjar.weixin.cp.bean.WxCpTpCorp; +import me.chanjar.weixin.cp.config.WxCpTpConfigStorage; + +/** + * 微信第三方应用API的Service. + * + * @author zhenjun cai + */ +public interface WxCpTpService { + String JSCODE_TO_SESSION_URL = "https://qyapi.weixin.qq.com/cgi-bin/service/miniprogram/jscode2session"; + String GET_CORP_TOKEN = "https://qyapi.weixin.qq.com/cgi-bin/service/get_corp_token"; + String GET_PERMANENT_CODE = "https://qyapi.weixin.qq.com/cgi-bin/service/get_permanent_code"; + String GET_SUITE_TOKEN = "https://qyapi.weixin.qq.com/cgi-bin/service/get_suite_token"; + + /** + *
+   * 验证推送过来的消息的正确性
+   * 详情请见: https://work.weixin.qq.com/api/doc#90000/90139/90968/消息体签名校验
+   * 
+ * + * @param msgSignature 消息签名 + * @param timestamp 时间戳 + * @param nonce 随机数 + * @param data 微信传输过来的数据,有可能是echoStr,有可能是xml消息 + */ + boolean checkSignature(String msgSignature, String timestamp, String nonce, String data); + + /** + * 获取suite_access_token, 不强制刷新suite_access_token + * + * @see #getSuiteAccessToken(boolean) + */ + String getSuiteAccessToken() throws WxErrorException; + + /** + *
+   * 获取suite_access_token,本方法线程安全
+   * 且在多线程同时刷新时只刷新一次,避免超出2000次/日的调用次数上限
+   * 另:本service的所有方法都会在suite_access_token过期是调用此方法
+   * 程序员在非必要情况下尽量不要主动调用此方法
+   * 详情请见: https://work.weixin.qq.com/api/doc#90001/90143/90600
+   * 
+ * + * @param forceRefresh 强制刷新 + */ + String getSuiteAccessToken(boolean forceRefresh) throws WxErrorException; + + /** + * 获得suite_ticket,不强制刷新suite_ticket + * + * @see #getSuiteTicket(boolean) + */ + String getSuiteTicket() throws WxErrorException; + + /** + *
+   * 获得suite_ticket
+   * 由于suite_ticket是微信服务器定时推送(每10分钟),不能主动获取,如果碰到过期只能抛异常
+   *
+   * 详情请见:https://work.weixin.qq.com/api/doc#90001/90143/90628
+   * 
+ * + * @param forceRefresh 强制刷新 + */ + String getSuiteTicket(boolean forceRefresh) throws WxErrorException; + + /** + * 小程序登录凭证校验 + * + * @param jsCode 登录时获取的 code + */ + WxCpMaJsCode2SessionResult jsCode2Session(String jsCode) throws WxErrorException; + + /** + * 获取企业凭证 + * + * @param authCorpid 授权方corpid + * @param permanentCode 永久授权码,通过get_permanent_code获取 + */ + WxAccessToken getCorpToken(String authCorpid, String permanentCode) throws WxErrorException; + + /** + * 获取企业永久授权码 + * + * @param authCode + * @return + */ + WxCpTpCorp getPermanentCode(String authCode) throws WxErrorException; + + /** + * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求 + * + * @param url 接口地址 + * @param queryParam 请求参数 + */ + String get(String url, String queryParam) throws WxErrorException; + + /** + * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求 + * + * @param url 接口地址 + * @param postData 请求body字符串 + */ + String post(String url, String postData) throws WxErrorException; + + /** + *
+   * Service没有实现某个API的时候,可以用这个,
+   * 比{@link #get}和{@link #post}方法更灵活,可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。
+   * 可以参考,{@link MediaUploadRequestExecutor}的实现方法
+   * 
+ * + * @param executor 执行器 + * @param uri 请求地址 + * @param data 参数 + * @param 请求值类型 + * @param 返回值类型 + */ + T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; + + /** + *
+   * 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试
+   * 默认:1000ms
+   * 
+ * + * @param retrySleepMillis 重试休息时间 + */ + void setRetrySleepMillis(int retrySleepMillis); + + /** + *
+   * 设置当微信系统响应系统繁忙时,最大重试次数
+   * 默认:5次
+   * 
+ * + * @param maxRetryTimes 最大重试次数 + */ + void setMaxRetryTimes(int maxRetryTimes); + + /** + * 初始化http请求对象 + */ + void initHttp(); + + /** + * 获取WxMpConfigStorage 对象 + * + * @return WxMpConfigStorage + */ + WxCpTpConfigStorage getWxCpTpConfigStorage(); + + /** + * 注入 {@link WxCpTpConfigStorage} 的实现 + * + * @param wxConfigProvider 配置对象 + */ + void setWxCpTpConfigStorage(WxCpTpConfigStorage wxConfigProvider); + + /** + * http请求对象 + */ + RequestHttp getRequestHttp(); + +} 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 310a1efa5e..091c687595 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 @@ -17,6 +17,19 @@ * @author Binary Wang */ public interface WxCpUserService { + String URL_AUTHENTICATE = "https://qyapi.weixin.qq.com/cgi-bin/user/authsucc?userid="; + String URL_USER_CREATE = "https://qyapi.weixin.qq.com/cgi-bin/user/create"; + String URL_USER_UPDATE = "https://qyapi.weixin.qq.com/cgi-bin/user/update"; + String URL_USER_DELETE = "https://qyapi.weixin.qq.com/cgi-bin/user/delete?userid="; + String URL_USER_BATCH_DELETE = "https://qyapi.weixin.qq.com/cgi-bin/user/batchdelete"; + String URL_USER_GET = "https://qyapi.weixin.qq.com/cgi-bin/user/get?userid="; + String URL_USER_LIST = "https://qyapi.weixin.qq.com/cgi-bin/user/list?department_id="; + String URL_USER_SIMPLE_LIST = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?department_id="; + String URL_BATCH_INVITE = "https://qyapi.weixin.qq.com/cgi-bin/batch/invite"; + String URL_CONVERT_TO_OPENID = "https://qyapi.weixin.qq.com/cgi-bin/user/convert_to_openid"; + String URL_CONVERT_TO_USERID = "https://qyapi.weixin.qq.com/cgi-bin/user/convert_to_userid"; + String URL_GET_EXTERNAL_CONTACT = "https://qyapi.weixin.qq.com/cgi-bin/crm/get_external_contact?external_userid="; + /** *
    *   用在二次验证的时候.
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java
index 3eb99b79d2..d9c88b47a5 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java
@@ -45,7 +45,7 @@ public abstract class BaseWxCpServiceImpl implements WxCpService, RequestH
   private WxCpOAuth2Service oauth2Service = new WxCpOAuth2ServiceImpl(this);
   private WxCpTagService tagService = new WxCpTagServiceImpl(this);
   private WxCpAgentService agentService = new WxCpAgentServiceImpl(this);
-  private WxCpOAService oaService = new WxCpOAServiceImpl(this);
+  private WxCpOaService oaService = new WxCpOaServiceImpl(this);
   private WxCpTaskCardService taskCardService = new WxCpTaskCardServiceImpl(this);
 
   /**
@@ -389,7 +389,7 @@ public WxCpChatService getChatService() {
   }
 
   @Override
-  public WxCpOAService getOAService() {
+  public WxCpOaService getOAService() {
     return oaService;
   }
 
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 3a977b81d8..10c417729e 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
@@ -37,15 +37,13 @@ public WxCpAgent get(Integer agentId) throws WxErrorException {
       throw new IllegalArgumentException("缺少agentid参数");
     }
 
-    String url = "https://qyapi.weixin.qq.com/cgi-bin/agent/get?agentid=" + agentId;
-    String responseContent = this.mainService.get(url, null);
+    String responseContent = this.mainService.get(String.format(WxCpAgentService.GET_AGENT, agentId), 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());
+    String responseContent = this.mainService.post(WxCpAgentService.AGENT_SET, agentInfo.toJson());
     JsonObject jsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject();
     if (jsonObject.get("errcode").getAsInt() != 0) {
       throw new WxErrorException(WxError.fromJson(responseContent));
@@ -54,8 +52,7 @@ public void set(WxCpAgent agentInfo) throws WxErrorException {
 
   @Override
   public List list() throws WxErrorException {
-    String url = "https://qyapi.weixin.qq.com/cgi-bin/agent/list";
-    String responseContent = this.mainService.get(url, null);
+    String responseContent = this.mainService.get(WxCpAgentService.AGENT_LIST, null);
     JsonObject jsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject();
     if (jsonObject.get("errcode").getAsInt() != 0) {
       throw new WxErrorException(WxError.fromJson(responseContent));
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java
index 05d298c9ad..0b1fb59381 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java
@@ -98,7 +98,7 @@ public WxCpChat get(String chatId) throws WxErrorException {
 
   @Override
   public void sendMsg(WxCpAppChatMessage message) throws WxErrorException {
-    this.cpService.post("https://qyapi.weixin.qq.com/cgi-bin/appchat/send", message.toJson());
+    this.cpService.post(WxCpChatService.APPCHAT_SEND, message.toJson());
   }
 
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java
index 481115fa51..09ded1b8b3 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java
@@ -29,27 +29,25 @@ public WxCpDepartmentServiceImpl(WxCpService mainService) {
 
   @Override
   public Long create(WxCpDepart depart) throws WxErrorException {
-    String url = "https://qyapi.weixin.qq.com/cgi-bin/department/create";
-    String responseContent = this.mainService.post(url, depart.toJson());
+    String responseContent = this.mainService.post(WxCpDepartmentService.DEPARTMENT_CREATE, depart.toJson());
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return GsonHelper.getAsLong(tmpJsonElement.getAsJsonObject().get("id"));
   }
 
   @Override
   public void update(WxCpDepart group) throws WxErrorException {
-    String url = "https://qyapi.weixin.qq.com/cgi-bin/department/update";
-    this.mainService.post(url, group.toJson());
+    this.mainService.post(WxCpDepartmentService.DEPARTMENT_UPDATE, group.toJson());
   }
 
   @Override
   public void delete(Long departId) throws WxErrorException {
-    String url = "https://qyapi.weixin.qq.com/cgi-bin/department/delete?id=" + departId;
+    String url = String.format(WxCpDepartmentService.DEPARTMENT_DELETE, departId);
     this.mainService.get(url, null);
   }
 
   @Override
   public List list(Long id) throws WxErrorException {
-    String url = "https://qyapi.weixin.qq.com/cgi-bin/department/list";
+    String url = WxCpDepartmentService.DEPARTMENT_LIST;
     if (id != null) {
       url += "?id=" + id;
     }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java
index f58eff4763..d33ade0191 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java
@@ -8,10 +8,11 @@
 
 /**
  * 
- * 菜单管理相关接口
+ * 菜单管理相关接口.
  * Created by Binary Wang on 2017-6-25.
- * @author Binary Wang
  * 
+ * + * @author Binary Wang */ public class WxCpMenuServiceImpl implements WxCpMenuService { private WxCpService mainService; @@ -27,8 +28,7 @@ public void create(WxMenu menu) throws WxErrorException { @Override public void create(Integer agentId, WxMenu menu) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?agentid=" + agentId; - this.mainService.post(url, menu.toJson()); + this.mainService.post(String.format(WxCpMenuService.MENU_CREATE, agentId), menu.toJson()); } @Override @@ -38,7 +38,7 @@ public void delete() throws WxErrorException { @Override public void delete(Integer agentId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/delete?agentid=" + agentId; + String url = String.format(WxCpMenuService.MENU_DELETE, agentId); this.mainService.get(url, null); } @@ -49,7 +49,7 @@ public WxMenu get() throws WxErrorException { @Override public WxMenu get(Integer agentId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/menu/get?agentid=" + agentId; + String url = String.format(WxCpMenuService.MENU_GET, agentId); try { String resultContent = this.mainService.get(url, null); return WxCpGsonBuilder.create().fromJson(resultContent, WxMenu.class); diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java similarity index 71% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAServiceImpl.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java index 2d1ca6ab0b..cc3b274495 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java @@ -6,7 +6,7 @@ import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; import me.chanjar.weixin.common.error.WxErrorException; -import me.chanjar.weixin.cp.api.WxCpOAService; +import me.chanjar.weixin.cp.api.WxCpOaService; import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.bean.WxCpApprovalDataResult; import me.chanjar.weixin.cp.bean.WxCpCheckinData; @@ -19,22 +19,19 @@ /** * @author Element - * @Package me.chanjar.weixin.cp.api.impl * @date 2019-04-06 11:20 - * @Description: TODO */ -public class WxCpOAServiceImpl implements WxCpOAService { - +public class WxCpOaServiceImpl implements WxCpOaService { private WxCpService mainService; - public WxCpOAServiceImpl(WxCpService mainService) { + public WxCpOaServiceImpl(WxCpService mainService) { this.mainService = mainService; } @Override - public List getCheckinData(Integer openCheckinDataType, Date starttime, Date endtime, List userIdList) throws WxErrorException { + public List getCheckinData(Integer openCheckinDataType, Date startTime, Date endTime, List userIdList) throws WxErrorException { - if (starttime == null || endtime == null) { + if (startTime == null || endTime == null) { throw new RuntimeException("starttime and endtime can't be null"); } @@ -42,15 +39,13 @@ public List getCheckinData(Integer openCheckinDataType, Date st throw new RuntimeException("用户列表不能为空,不超过100个,若用户超过100个,请分批获取"); } - long endtimestamp = endtime.getTime() / 1000L; - long starttimestamp = starttime.getTime() / 1000L; + long endtimestamp = endTime.getTime() / 1000L; + long starttimestamp = startTime.getTime() / 1000L; if (endtimestamp - starttimestamp < 0 || endtimestamp - starttimestamp >= 30 * 24 * 60 * 60) { throw new RuntimeException("获取记录时间跨度不超过一个月"); } - String url = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckindata"; - JsonObject jsonObject = new JsonObject(); JsonArray jsonArray = new JsonArray(); @@ -64,7 +59,7 @@ public List getCheckinData(Integer openCheckinDataType, Date st jsonObject.add("useridlist", jsonArray); - String responseContent = this.mainService.post(url, jsonObject.toString()); + String responseContent = this.mainService.post(WxCpOaService.GET_CHECKIN_DATA, jsonObject.toString()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return WxCpGsonBuilder.create() .fromJson( @@ -76,7 +71,6 @@ public List getCheckinData(Integer openCheckinDataType, Date st @Override public List getCheckinOption(Date datetime, List userIdList) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckinoption"; if (datetime == null) { throw new RuntimeException("datetime can't be null"); } @@ -94,7 +88,7 @@ public List getCheckinOption(Date datetime, List user jsonObject.addProperty("datetime", datetime.getTime() / 1000L); jsonObject.add("useridlist", jsonArray); - String responseContent = this.mainService.post(url, jsonObject.toString()); + String responseContent = this.mainService.post(WxCpOaService.GET_CHECKIN_OPTION, jsonObject.toString()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return WxCpGsonBuilder.create() @@ -106,24 +100,20 @@ public List getCheckinOption(Date datetime, List user } @Override - public WxCpApprovalDataResult getApprovalData(Date starttime, Date endtime, Long nextSpnum) throws WxErrorException { - - String url = "https://qyapi.weixin.qq.com/cgi-bin/corp/getapprovaldata"; + public WxCpApprovalDataResult getApprovalData(Date startTime, Date endTime, Long nextSpnum) throws WxErrorException { JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("starttime", starttime.getTime() / 1000L); - jsonObject.addProperty("endtime", endtime.getTime() / 1000L); + jsonObject.addProperty("starttime", startTime.getTime() / 1000L); + jsonObject.addProperty("endtime", endTime.getTime() / 1000L); if (nextSpnum != null) { jsonObject.addProperty("next_spnum", nextSpnum); } - String responseContent = this.mainService.post(url, jsonObject.toString()); + String responseContent = this.mainService.post(WxCpOaService.GET_APPROVAL_DATA, jsonObject.toString()); return WxCpGsonBuilder.create().fromJson(responseContent, WxCpApprovalDataResult.class); } @Override - public List getDialRecord(Date starttime, Date endtime, Integer offset, Integer limit) throws WxErrorException { - - String url = "https://qyapi.weixin.qq.com/cgi-bin/dial/get_dial_record"; + public List getDialRecord(Date startTime, Date endTime, Integer offset, Integer limit) throws WxErrorException { JsonObject jsonObject = new JsonObject(); if (offset == null) { @@ -137,10 +127,10 @@ public List getDialRecord(Date starttime, Date endtime, Integer jsonObject.addProperty("offset", offset); jsonObject.addProperty("limit", limit); - if (starttime != null && endtime != null) { + if (startTime != null && endTime != null) { - long endtimestamp = endtime.getTime() / 1000L; - long starttimestamp = starttime.getTime() / 1000L; + long endtimestamp = endTime.getTime() / 1000L; + long starttimestamp = startTime.getTime() / 1000L; if (endtimestamp - starttimestamp < 0 || endtimestamp - starttimestamp >= 30 * 24 * 60 * 60) { throw new RuntimeException("受限于网络传输,起止时间的最大跨度为30天,如超过30天,则以结束时间为基准向前取30天进行查询"); @@ -148,11 +138,9 @@ public List getDialRecord(Date starttime, Date endtime, Integer jsonObject.addProperty("start_time", starttimestamp); jsonObject.addProperty("end_time", endtimestamp); - - } - String responseContent = this.mainService.post(url, jsonObject.toString()); + String responseContent = this.mainService.post(WxCpOaService.GET_DIAL_RECORD, jsonObject.toString()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return WxCpGsonBuilder.create() diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java index 86e237168d..11a183b507 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java @@ -8,7 +8,7 @@ import me.chanjar.weixin.common.util.http.HttpType; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; -import me.chanjar.weixin.cp.api.WxCpOAService; +import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.config.WxCpConfigStorage; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; @@ -19,6 +19,9 @@ import java.io.IOException; +/** + * @author someone + */ public class WxCpServiceApacheHttpClientImpl extends BaseWxCpServiceImpl { protected CloseableHttpClient httpClient; protected HttpHost httpProxy; @@ -45,9 +48,7 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { } synchronized (this.globalAccessTokenRefreshLock) { - String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?" - + "&corpid=" + this.configStorage.getCorpId() - + "&corpsecret=" + this.configStorage.getCorpSecret(); + String url = String.format(WxCpService.GET_TOKEN, this.configStorage.getCorpId(), this.configStorage.getCorpSecret()); try { HttpGet httpGet = new HttpGet(url); if (this.httpProxy != null) { @@ -56,8 +57,8 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { httpGet.setConfig(config); } String resultContent; - try (CloseableHttpClient httpclient = getRequestHttpClient(); - CloseableHttpResponse response = httpclient.execute(httpGet)) { + try (CloseableHttpClient httpClient = getRequestHttpClient(); + CloseableHttpResponse response = httpClient.execute(httpGet)) { resultContent = new BasicResponseHandler().handleResponse(response); } finally { httpGet.releaseConnection(); diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java index 3603a59b17..d5d08900b9 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java @@ -6,8 +6,12 @@ import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.HttpType; +import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.config.WxCpConfigStorage; +/** + * @author someone + */ public class WxCpServiceJoddHttpImpl extends BaseWxCpServiceImpl { protected HttpConnectionProvider httpClient; protected ProxyInfo httpProxy; @@ -35,11 +39,7 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { } synchronized (this.globalAccessTokenRefreshLock) { - String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?" - + "&corpid=" + this.configStorage.getCorpId() - + "&corpsecret=" + this.configStorage.getCorpSecret(); - - HttpRequest request = HttpRequest.get(url); + HttpRequest request = HttpRequest.get(String.format(WxCpService.GET_TOKEN, this.configStorage.getCorpId(), this.configStorage.getCorpSecret())); if (this.httpProxy != null) { httpClient.useProxy(this.httpProxy); } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java index 9163ce03a6..f4cc540f3c 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java @@ -6,15 +6,18 @@ import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.HttpType; import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; +import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.config.WxCpConfigStorage; import okhttp3.*; import java.io.IOException; +/** + * @author someone + */ public class WxCpServiceOkHttpImpl extends BaseWxCpServiceImpl { - protected OkHttpClient httpClient; - protected OkHttpProxyInfo httpProxy; - + private OkHttpClient httpClient; + private OkHttpProxyInfo httpProxy; @Override public OkHttpClient getRequestHttpClient() { @@ -38,28 +41,28 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { } synchronized (this.globalAccessTokenRefreshLock) { - String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?" - + "&corpid=" + this.configStorage.getCorpId() - + "&corpsecret=" + this.configStorage.getCorpSecret(); - //得到httpClient - OkHttpClient client = getRequestHttpClient(); - //请求的request - Request request = new Request.Builder().url(url).get().build(); - String resultContent = null; - try { - Response response = client.newCall(request).execute(); - resultContent = response.body().string(); - } catch (IOException e) { - this.log.error(e.getMessage(), e); - } + //得到httpClient + OkHttpClient client = getRequestHttpClient(); + //请求的request + Request request = new Request.Builder() + .url(String.format(WxCpService.GET_TOKEN, this.configStorage.getCorpId(), this.configStorage.getCorpSecret())) + .get() + .build(); + String resultContent = null; + try { + Response response = client.newCall(request).execute(); + resultContent = response.body().string(); + } catch (IOException e) { + this.log.error(e.getMessage(), e); + } - WxError error = WxError.fromJson(resultContent, WxType.CP); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); - this.configStorage.updateAccessToken(accessToken.getAccessToken(), - accessToken.getExpiresIn()); + WxError error = WxError.fromJson(resultContent, WxType.CP); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); + this.configStorage.updateAccessToken(accessToken.getAccessToken(), + accessToken.getExpiresIn()); } return this.configStorage.getAccessToken(); } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java index 22bb0fcf96..413436207f 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java @@ -1,12 +1,6 @@ package me.chanjar.weixin.cp.api.impl; -import java.util.List; - -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.*; import com.google.gson.reflect.TypeToken; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.cp.api.WxCpService; @@ -17,12 +11,15 @@ import me.chanjar.weixin.cp.bean.WxCpUser; import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; +import java.util.List; + /** *
- *  标签管理接口
+ *  标签管理接口.
  * Created by Binary Wang on 2017-6-25.
- * @author Binary Wang
  * 
+ * + * @author Binary Wang */ public class WxCpTagServiceImpl implements WxCpTagService { private WxCpService mainService; @@ -33,33 +30,29 @@ public WxCpTagServiceImpl(WxCpService mainService) { @Override public String create(String tagName) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/create"; JsonObject o = new JsonObject(); o.addProperty("tagname", tagName); - String responseContent = this.mainService.post(url, o.toString()); + String responseContent = this.mainService.post(WxCpTagService.TAG_CREATE, o.toString()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return tmpJsonElement.getAsJsonObject().get("tagid").getAsString(); } @Override public void update(String tagId, String tagName) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/update"; JsonObject o = new JsonObject(); o.addProperty("tagid", tagId); o.addProperty("tagname", tagName); - this.mainService.post(url, o.toString()); + this.mainService.post(WxCpTagService.TAG_UPDATE, o.toString()); } @Override public void delete(String tagId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/delete?tagid=" + tagId; - this.mainService.get(url, null); + this.mainService.get(String.format(WxCpTagService.TAG_DELETE, tagId), null); } @Override public List listAll() throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/list"; - String responseContent = this.mainService.get(url, null); + String responseContent = this.mainService.get(WxCpTagService.TAG_LIST, null); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return WxCpGsonBuilder.create() .fromJson( @@ -71,8 +64,7 @@ public List listAll() throws WxErrorException { @Override public List listUsersByTagId(String tagId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/get?tagid=" + tagId; - String responseContent = this.mainService.get(url, null); + String responseContent = this.mainService.get(String.format(WxCpTagService.TAG_GET, tagId), null); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return WxCpGsonBuilder.create() .fromJson( @@ -84,22 +76,20 @@ public List listUsersByTagId(String tagId) throws WxErrorException { @Override public WxCpTagAddOrRemoveUsersResult addUsers2Tag(String tagId, List userIds, List partyIds) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/addtagusers"; JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("tagid", tagId); this.addUserIdsAndPartyIdsToJson(userIds, partyIds, jsonObject); - return WxCpTagAddOrRemoveUsersResult.fromJson(this.mainService.post(url, jsonObject.toString())); + return WxCpTagAddOrRemoveUsersResult.fromJson(this.mainService.post(WxCpTagService.TAG_ADDTAGUSERS, jsonObject.toString())); } @Override public WxCpTagAddOrRemoveUsersResult removeUsersFromTag(String tagId, List userIds, List partyIds) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/deltagusers"; JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("tagid", tagId); this.addUserIdsAndPartyIdsToJson(userIds, partyIds, jsonObject); - return WxCpTagAddOrRemoveUsersResult.fromJson(this.mainService.post(url, jsonObject.toString())); + return WxCpTagAddOrRemoveUsersResult.fromJson(this.mainService.post(WxCpTagService.TAG_DELTAGUSERS, jsonObject.toString())); } private void addUserIdsAndPartyIdsToJson(List userIds, List partyIds, JsonObject jsonObject) { @@ -122,15 +112,11 @@ private void addUserIdsAndPartyIdsToJson(List userIds, List part @Override public WxCpTagGetResult get(String tagId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/tag/get"; - if (tagId != null) { - url += "?tagId=" + tagId; - } else { + if (tagId == null) { throw new IllegalArgumentException("缺少tagId参数"); } - String responseContent = this.mainService.get(url, null); - + String responseContent = this.mainService.get(String.format(WxCpTagService.TAG_GET, tagId), null); return WxCpTagGetResult.fromJson(responseContent); } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTaskCardServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTaskCardServiceImpl.java index 3011320d50..e70a7d376a 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTaskCardServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTaskCardServiceImpl.java @@ -33,7 +33,6 @@ public void update(List userIds, String taskId, String clickedKey) throw data.put("task_id", taskId); data.put("clicked_key", clickedKey); - String url = "https://qyapi.weixin.qq.com/cgi-bin/message/update_taskcard"; - this.mainService.post(url, WxGsonBuilder.create().toJson(data)); + this.mainService.post(MESSAGE_UPDATE_TASKCARD, WxGsonBuilder.create().toJson(data)); } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceApacheHttpClientImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceApacheHttpClientImpl.java index 0b8a134d48..f673a622bd 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceApacheHttpClientImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceApacheHttpClientImpl.java @@ -1,114 +1,114 @@ -package me.chanjar.weixin.cp.api.impl; - - -import java.io.IOException; - -import org.apache.http.Consts; -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.HttpPost; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.BasicResponseHandler; -import org.apache.http.impl.client.CloseableHttpClient; - -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; - -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.http.HttpType; -import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; -import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; -import me.chanjar.weixin.cp.config.WxCpTpConfigStorage; - -public class WxCpTpServiceApacheHttpClientImpl extends BaseWxCpTpServiceImpl { - protected CloseableHttpClient httpClient; - protected HttpHost httpProxy; - - @Override - public CloseableHttpClient getRequestHttpClient() { - return httpClient; - } - - @Override - public HttpHost getRequestHttpProxy() { - return httpProxy; - } - - @Override - public HttpType getRequestType() { - return HttpType.APACHE_HTTP; - } - - @Override - public String getSuiteAccessToken(boolean forceRefresh) throws WxErrorException { - if (!this.configStorage.isSuiteAccessTokenExpired() && !forceRefresh) { - return this.configStorage.getSuiteAccessToken(); - } - - synchronized (this.globalSuiteAccessTokenRefreshLock) { - String url = "https://qyapi.weixin.qq.com/cgi-bin/service/get_suite_token"; - try { - HttpPost httpPost = new HttpPost(url); - if (this.httpProxy != null) { - RequestConfig config = RequestConfig.custom() - .setProxy(this.httpProxy).build(); - httpPost.setConfig(config); - } - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("suite_id", this.configStorage.getSuiteId()); - jsonObject.addProperty("suite_secret", this.configStorage.getSuiteSecret()); - jsonObject.addProperty("suite_ticket", this.getSuiteTicket()); - StringEntity entity = new StringEntity(jsonObject.toString(), Consts.UTF_8); - httpPost.setEntity(entity); - - String resultContent; - try (CloseableHttpClient httpclient = getRequestHttpClient(); - CloseableHttpResponse response = httpclient.execute(httpPost)) { - resultContent = new BasicResponseHandler().handleResponse(response); - } finally { - httpPost.releaseConnection(); - } - WxError error = WxError.fromJson(resultContent, WxType.CP); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - jsonObject = new JsonParser().parse(resultContent).getAsJsonObject(); - String suiteAccussToken = jsonObject.get("suite_access_token").getAsString(); - Integer expiresIn = jsonObject.get("expires_in").getAsInt(); - this.configStorage.updateSuiteAccessToken(suiteAccussToken, expiresIn); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - return this.configStorage.getSuiteAccessToken(); - } - - @Override - public void initHttp() { - ApacheHttpClientBuilder apacheHttpClientBuilder = this.configStorage - .getApacheHttpClientBuilder(); - if (null == apacheHttpClientBuilder) { - apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get(); - } - - apacheHttpClientBuilder.httpProxyHost(this.configStorage.getHttpProxyHost()) - .httpProxyPort(this.configStorage.getHttpProxyPort()) - .httpProxyUsername(this.configStorage.getHttpProxyUsername()) - .httpProxyPassword(this.configStorage.getHttpProxyPassword()); - - if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) { - this.httpProxy = new HttpHost(this.configStorage.getHttpProxyHost(), this.configStorage.getHttpProxyPort()); - } - - this.httpClient = apacheHttpClientBuilder.build(); - } - - @Override - public WxCpTpConfigStorage getWxCpTpConfigStorage() { - return this.configStorage; - } - -} +package me.chanjar.weixin.cp.api.impl; + + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +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.http.HttpType; +import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; +import me.chanjar.weixin.cp.api.WxCpTpService; +import me.chanjar.weixin.cp.config.WxCpTpConfigStorage; +import org.apache.http.Consts; +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.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.BasicResponseHandler; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.IOException; + +/** + * @author someone + */ +public class WxCpTpServiceApacheHttpClientImpl extends BaseWxCpTpServiceImpl { + private CloseableHttpClient httpClient; + private HttpHost httpProxy; + + @Override + public CloseableHttpClient getRequestHttpClient() { + return httpClient; + } + + @Override + public HttpHost getRequestHttpProxy() { + return httpProxy; + } + + @Override + public HttpType getRequestType() { + return HttpType.APACHE_HTTP; + } + + @Override + public String getSuiteAccessToken(boolean forceRefresh) throws WxErrorException { + if (!this.configStorage.isSuiteAccessTokenExpired() && !forceRefresh) { + return this.configStorage.getSuiteAccessToken(); + } + + synchronized (this.globalSuiteAccessTokenRefreshLock) { + try { + HttpPost httpPost = new HttpPost(WxCpTpService.GET_SUITE_TOKEN); + if (this.httpProxy != null) { + RequestConfig config = RequestConfig.custom() + .setProxy(this.httpProxy).build(); + httpPost.setConfig(config); + } + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("suite_id", this.configStorage.getSuiteId()); + jsonObject.addProperty("suite_secret", this.configStorage.getSuiteSecret()); + jsonObject.addProperty("suite_ticket", this.getSuiteTicket()); + StringEntity entity = new StringEntity(jsonObject.toString(), Consts.UTF_8); + httpPost.setEntity(entity); + + String resultContent; + try (CloseableHttpClient httpclient = getRequestHttpClient(); + CloseableHttpResponse response = httpclient.execute(httpPost)) { + resultContent = new BasicResponseHandler().handleResponse(response); + } finally { + httpPost.releaseConnection(); + } + WxError error = WxError.fromJson(resultContent, WxType.CP); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + jsonObject = new JsonParser().parse(resultContent).getAsJsonObject(); + String suiteAccussToken = jsonObject.get("suite_access_token").getAsString(); + Integer expiresIn = jsonObject.get("expires_in").getAsInt(); + this.configStorage.updateSuiteAccessToken(suiteAccussToken, expiresIn); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return this.configStorage.getSuiteAccessToken(); + } + + @Override + public void initHttp() { + ApacheHttpClientBuilder apacheHttpClientBuilder = this.configStorage.getApacheHttpClientBuilder(); + if (null == apacheHttpClientBuilder) { + apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get(); + } + + apacheHttpClientBuilder.httpProxyHost(this.configStorage.getHttpProxyHost()) + .httpProxyPort(this.configStorage.getHttpProxyPort()) + .httpProxyUsername(this.configStorage.getHttpProxyUsername()) + .httpProxyPassword(this.configStorage.getHttpProxyPassword()); + + if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) { + this.httpProxy = new HttpHost(this.configStorage.getHttpProxyHost(), this.configStorage.getHttpProxyPort()); + } + + this.httpClient = apacheHttpClientBuilder.build(); + } + + @Override + public WxCpTpConfigStorage getWxCpTpConfigStorage() { + return this.configStorage; + } + +} 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 84a16f3496..b3b0909522 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 @@ -26,7 +26,7 @@ * @author Binary Wang */ public class WxCpUserServiceImpl implements WxCpUserService { - private WxCpService mainService; + private final WxCpService mainService; public WxCpUserServiceImpl(WxCpService mainService) { this.mainService = mainService; @@ -34,50 +34,44 @@ public WxCpUserServiceImpl(WxCpService mainService) { @Override public void authenticate(String userId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/authsucc?userid=" + userId; - this.mainService.get(url, null); + this.mainService.get(WxCpUserService.URL_AUTHENTICATE + userId, null); } @Override public void create(WxCpUser user) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/create"; - this.mainService.post(url, user.toJson()); + this.mainService.post(WxCpUserService.URL_USER_CREATE, user.toJson()); } @Override public void update(WxCpUser user) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/update"; - this.mainService.post(url, user.toJson()); + this.mainService.post(WxCpUserService.URL_USER_UPDATE, user.toJson()); } @Override public void delete(String... userIds) throws WxErrorException { if (userIds.length == 1) { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/delete?userid=" + userIds[0]; - this.mainService.get(url, null); + this.mainService.get(WxCpUserService.URL_USER_DELETE + userIds[0], null); return; } - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/batchdelete"; JsonObject jsonObject = new JsonObject(); JsonArray jsonArray = new JsonArray(); - for (String userid : userIds) { - jsonArray.add(new JsonPrimitive(userid)); + for (String userId : userIds) { + jsonArray.add(new JsonPrimitive(userId)); } + jsonObject.add("useridlist", jsonArray); - this.mainService.post(url, jsonObject.toString()); + this.mainService.post(WxCpUserService.URL_USER_BATCH_DELETE, jsonObject.toString()); } @Override public WxCpUser getById(String userid) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/get?userid=" + userid; - String responseContent = this.mainService.get(url, null); + String responseContent = this.mainService.get(WxCpUserService.URL_USER_GET + userid, null); return WxCpUser.fromJson(responseContent); } @Override public List listByDepartment(Long departId, Boolean fetchChild, Integer status) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/list?department_id=" + departId; String params = ""; if (fetchChild != null) { params += "&fetch_child=" + (fetchChild ? "1" : "0"); @@ -88,7 +82,7 @@ public List listByDepartment(Long departId, Boolean fetchChild, Intege params += "&status=0"; } - String responseContent = this.mainService.get(url, params); + String responseContent = this.mainService.get(WxCpUserService.URL_USER_LIST + departId, params); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return WxCpGsonBuilder.create() .fromJson(tmpJsonElement.getAsJsonObject().get("userlist"), @@ -99,7 +93,6 @@ public List listByDepartment(Long departId, Boolean fetchChild, Intege @Override public List listSimpleByDepartment(Long departId, Boolean fetchChild, Integer status) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?department_id=" + departId; String params = ""; if (fetchChild != null) { params += "&fetch_child=" + (fetchChild ? "1" : "0"); @@ -110,7 +103,7 @@ public List listSimpleByDepartment(Long departId, Boolean fetchChild, params += "&status=0"; } - String responseContent = this.mainService.get(url, params); + String responseContent = this.mainService.get(WxCpUserService.URL_USER_SIMPLE_LIST + departId, params); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); return WxCpGsonBuilder.create() .fromJson( @@ -122,7 +115,6 @@ public List listSimpleByDepartment(Long departId, Boolean fetchChild, @Override public WxCpInviteResult invite(List userIds, List partyIds, List tagIds) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/invite"; JsonObject jsonObject = new JsonObject(); if (userIds != null) { JsonArray jsonArray = new JsonArray(); @@ -148,19 +140,18 @@ public WxCpInviteResult invite(List userIds, List partyIds, List jsonObject.add("tag", jsonArray); } - return WxCpInviteResult.fromJson(this.mainService.post(url, jsonObject.toString())); + return WxCpInviteResult.fromJson(this.mainService.post(WxCpUserService.URL_BATCH_INVITE, jsonObject.toString())); } @Override public Map userId2Openid(String userId, Integer agentId) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/convert_to_openid"; JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("userid", userId); if (agentId != null) { jsonObject.addProperty("agentid", agentId); } - String responseContent = this.mainService.post(url, jsonObject.toString()); + String responseContent = this.mainService.post(WxCpUserService.URL_CONVERT_TO_OPENID, jsonObject.toString()); JsonElement tmpJsonElement = new JsonParser().parse(responseContent); Map result = Maps.newHashMap(); if (tmpJsonElement.getAsJsonObject().get("openid") != null) { @@ -176,18 +167,16 @@ public Map userId2Openid(String userId, Integer agentId) throws @Override public String openid2UserId(String openid) throws WxErrorException { - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/convert_to_userid"; JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("openid", openid); - String responseContent = this.mainService.post(url, jsonObject.toString()); + String responseContent = this.mainService.post(WxCpUserService.URL_CONVERT_TO_USERID, jsonObject.toString()); 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); + String responseContent = this.mainService.get(WxCpUserService.URL_GET_EXTERNAL_CONTACT + userId, null); return WxCpUserExternalContactInfo.fromJson(responseContent); } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTagGetResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTagGetResult.java index 28cc4807a1..244419b062 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTagGetResult.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTagGetResult.java @@ -29,19 +29,19 @@ public class WxCpTagGetResult implements Serializable { private String errmsg; /** - * 用户列表 + * 用户列表. */ @SerializedName("userlist") private List userlist; /** - * 部门列表 + * 部门列表. */ @SerializedName("partylist") private List partylist; /** - * 标签名称 + * 标签名称. */ @SerializedName("tagname") private String tagname; 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 4ce497243d..a2dc46e826 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 @@ -6,7 +6,6 @@ import me.chanjar.weixin.cp.api.WxCpAgentService; import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.bean.WxCpAgent; -import org.testng.Assert; import org.testng.annotations.Guice; import org.testng.annotations.Test; @@ -71,7 +70,7 @@ public static class MockTest { @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.get(String.format(WxCpAgentService.GET_AGENT, 9), null)).thenReturn(returnJson); when(wxService.getAgentService()).thenReturn(new WxCpAgentServiceImpl(wxService)); WxCpAgentService wxAgentService = this.wxService.getAgentService(); diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOAServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImplTest.java similarity index 97% rename from weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOAServiceImplTest.java rename to weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImplTest.java index 9497a5626b..4810cd81d9 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOAServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImplTest.java @@ -24,7 +24,7 @@ * @date 2019-04-20 13:46 */ @Guice(modules = ApiTestModule.class) -public class WxCpOAServiceImplTest { +public class WxCpOaServiceImplTest { @Inject protected WxCpService wxService; diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java index 5a6e8ccabd..c4c8b3ccb5 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java @@ -22,10 +22,10 @@ /** *
- *
  * Created by Binary Wang on 2017-6-25.
- * @author Binary Wang
  * 
+ * + * @author Binary Wang */ @Guice(modules = ApiTestModule.class) public class WxCpTagServiceImplTest { @@ -35,7 +35,7 @@ public class WxCpTagServiceImplTest { @Inject protected ApiTestModule.WxXmlCpInMemoryConfigStorage configStorage; - protected String tagId; + private String tagId; @Test public void testCreate() throws Exception { @@ -83,7 +83,7 @@ public void testDelete() throws Exception { public void testGet() throws WxErrorException { String apiResultJson = "{\"errcode\": 0,\"errmsg\": \"ok\",\"userlist\": [{\"userid\": \"0124035\",\"name\": \"王五\"},{\"userid\": \"0114035\",\"name\": \"梦雪\"}],\"partylist\": [9576,9567,9566],\"tagname\": \"测试标签-001\"}"; WxCpService wxService = mock(WxCpService.class); - when(wxService.get("https://qyapi.weixin.qq.com/cgi-bin/tag/get?tagId=150", null)).thenReturn(apiResultJson); + when(wxService.get(String.format(WxCpTagService.TAG_GET, 150), null)).thenReturn(apiResultJson); when(wxService.getTagService()).thenReturn(new WxCpTagServiceImpl(wxService)); WxCpTagService wxCpTagService = wxService.getTagService(); @@ -96,7 +96,6 @@ public void testGet() throws WxErrorException { assertEquals(3, wxCpTagGetResult.getPartylist().size()); assertEquals("测试标签-001", wxCpTagGetResult.getTagname()); - } } 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 b39e76fdba..73793a23ff 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 @@ -3,6 +3,7 @@ import java.io.Serializable; import java.math.BigDecimal; +import lombok.experimental.Accessors; import org.apache.commons.lang3.StringUtils; import com.github.binarywang.wxpay.config.WxPayConfig; @@ -27,6 +28,7 @@ * @author Binary Wang */ @Data +@Accessors(chain = true) public abstract class BaseWxPayRequest implements Serializable { private static final long serialVersionUID = -4766915659779847060L; diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java index 78bb789d25..bf29a55b35 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java @@ -5,6 +5,7 @@ import com.github.binarywang.wxpay.exception.WxPayException; import com.thoughtworks.xstream.annotations.XStreamAlias; import lombok.*; +import lombok.experimental.Accessors; import me.chanjar.weixin.common.annotation.Required; import org.apache.commons.lang3.StringUtils; @@ -23,6 +24,7 @@ @NoArgsConstructor @AllArgsConstructor @XStreamAlias("xml") +@Accessors(chain = true) public class WxPayUnifiedOrderRequest extends BaseWxPayRequest { private static final long serialVersionUID = 4611350167813931828L; From f71fed4c6a311e152b4fec9656e277b7baaace61 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 2 Jun 2019 12:43:02 +0800 Subject: [PATCH 07/74] =?UTF-8?q?#1060=20=E4=BF=AE=E5=A4=8D=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E5=8D=A1=E5=88=B8=E7=AD=BE=E5=90=8D=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/common/util/crypto/SHA1.java | 8 +- .../weixin/mp/api/WxMpCardService.java | 43 +++--- .../mp/api/impl/WxMpCardServiceImpl.java | 134 +++--------------- .../mp/bean/card/WxMpCardDeleteResult.java | 8 +- 4 files changed, 51 insertions(+), 142 deletions(-) diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java index 3cdc572387..c82f94d871 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java @@ -6,12 +6,14 @@ import java.util.Arrays; /** - * Created by Daniel Qian on 14/10/19. + * + * @author Daniel Qian + * @date 14/10/19 */ public class SHA1 { /** - * 串接arr参数,生成sha1 digest + * 串接arr参数,生成sha1 digest. */ public static String gen(String... arr) { if (StringUtils.isAnyEmpty(arr)) { @@ -27,7 +29,7 @@ public static String gen(String... arr) { } /** - * 用&串接arr参数,生成sha1 digest + * 用&串接arr参数,生成sha1 digest. */ public static String genWithAmple(String... arr) { if (StringUtils.isAnyEmpty(arr)) { 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 66aeccade7..e7f2db4f87 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 @@ -3,10 +3,9 @@ import me.chanjar.weixin.common.bean.WxCardApiSignature; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.bean.card.*; -import me.chanjar.weixin.mp.bean.card.WxMpCardResult; /** - * 卡券相关接口 + * 卡券相关接口. * * @author YuJian(mgcnrx11 @ hotmail.com) on 01/11/2016 * @author yuanqixun 2018-08-29 @@ -22,23 +21,24 @@ public interface WxMpCardService { String CARD_TEST_WHITELIST = "https://api.weixin.qq.com/card/testwhitelist/set"; String CARD_QRCODE_CREATE = "https://api.weixin.qq.com/card/qrcode/create"; String CARD_LANDING_PAGE_CREATE = "https://api.weixin.qq.com/card/landingpage/create"; + /** - * 将用户的卡券设置为失效状态 + * 将用户的卡券设置为失效状态. */ String CARD_CODE_UNAVAILABLE = "https://api.weixin.qq.com/card/code/unavailable"; /** - * 卡券删除 + * 卡券删除. */ String CARD_DELETE = "https://api.weixin.qq.com/card/delete"; /** - * 得到WxMpService + * 得到WxMpService. */ WxMpService getWxMpService(); /** - * 获得卡券api_ticket,不强制刷新卡券api_ticket + * 获得卡券api_ticket,不强制刷新卡券api_ticket. * * @return 卡券api_ticket * @see #getCardApiTicket(boolean) @@ -47,7 +47,7 @@ public interface WxMpCardService { /** *
-   * 获得卡券api_ticket
+   * 获得卡券api_ticket.
    * 获得时会检查卡券apiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干
    *
    * 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD.954-.E5.8D.A1.E5.88.B8.E6.89.A9.E5.B1.95.E5.AD.97.E6.AE.B5.E5.8F.8A.E7.AD.BE.E5.90.8D.E7.94.9F.E6.88.90.E7.AE.97.E6.B3.95
@@ -61,7 +61,7 @@ public interface WxMpCardService {
 
   /**
    * 
-   * 创建调用卡券api时所需要的签名
+   * 创建调用卡券api时所需要的签名.
    *
    * 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD
    * .954-.E5.8D.A1.E5.88.B8.E6.89.A9.E5.B1.95.E5.AD.97.E6.AE.B5.E5.8F.8A.E7.AD.BE.E5.90.8D.E7.94
@@ -73,11 +73,10 @@ public interface WxMpCardService {
    *                          
注意:当做wx.chooseCard调用时,必须传入app_id参与签名,否则会造成签名失败导致拉取卡券列表为空 * @return 卡券Api签名对象 */ - WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws - WxErrorException; + WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws WxErrorException; /** - * 卡券Code解码 + * 卡券Code解码. * * @param encryptCode 加密Code,通过JSSDK的chooseCard接口获得 * @return 解密后的Code @@ -87,6 +86,7 @@ WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws /** * 卡券Code查询. * 文档地址: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1451025272&anchor=1 + * * @param cardId 卡券ID代表一类卡券 * @param code 单张卡券的唯一标准 * @param checkConsume 是否校验code核销状态,填入true和false时的code异常状态返回数据不同 @@ -105,7 +105,7 @@ WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) String consumeCardCode(String code) throws WxErrorException; /** - * 卡券Code核销。核销失败会抛出异常 + * 卡券Code核销。核销失败会抛出异常. * * @param code 单张卡券的唯一标准 * @param cardId 当自定义Code卡券时需要传入card_id @@ -124,11 +124,10 @@ WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) * @param openId 用券用户的openid * @param isMark 是否要mark(占用)这个code,填写true或者false,表示占用或解除占用 */ - void markCardCode(String code, String cardId, String openId, boolean isMark) throws - WxErrorException; + void markCardCode(String code, String cardId, String openId, boolean isMark) throws WxErrorException; /** - * 查看卡券详情接口 + * 查看卡券详情接口. * 详见 https://mp.weixin.qq.com/wiki/14/8dd77aeaee85f922db5f8aa6386d385e.html#.E6.9F.A5.E7.9C.8B.E5.8D.A1.E5.88.B8.E8.AF.A6.E6.83.85 * * @param cardId 卡券的ID @@ -139,7 +138,7 @@ void markCardCode(String code, String cardId, String openId, boolean isMark) thr String getCardDetail(String cardId) throws WxErrorException; /** - * 添加测试白名单 + * 添加测试白名单. * * @param openid 用户的openid * @return @@ -147,7 +146,6 @@ void markCardCode(String code, String cardId, String openId, boolean isMark) thr String addTestWhiteList(String openid) throws WxErrorException; /** - * * @param cardCreateMessage * @return * @throws WxErrorException @@ -155,7 +153,7 @@ void markCardCode(String code, String cardId, String openId, boolean isMark) thr WxMpCardCreateResult createCard(WxMpCardCreateMessage cardCreateMessage) throws WxErrorException; /** - * 创建卡券二维码 + * 创建卡券二维码. * * @param cardId 卡券编号 * @param outerStr 二维码标识 @@ -164,7 +162,7 @@ void markCardCode(String code, String cardId, String openId, boolean isMark) thr WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr) throws WxErrorException; /** - * 创建卡券二维码 + * 创建卡券二维码. * * @param cardId 卡券编号 * @param outerStr 二维码标识 @@ -174,7 +172,7 @@ void markCardCode(String code, String cardId, String openId, boolean isMark) thr WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr, int expiresIn) throws WxErrorException; /** - * 创建卡券货架 + * 创建卡券货架. * * @param createRequest 货架创建参数 * @return @@ -183,7 +181,7 @@ void markCardCode(String code, String cardId, String openId, boolean isMark) thr WxMpCardLandingPageCreateResult createLandingPage(WxMpCardLandingPageCreateRequest createRequest) throws WxErrorException; /** - * 将用户的卡券设置为失效状态 + * 将用户的卡券设置为失效状态. * 详见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1451025272&anchor=9 * * @param cardId 卡券编号 @@ -195,7 +193,8 @@ void markCardCode(String code, String cardId, String openId, boolean isMark) thr String unavailableCardCode(String cardId, String code, String reason) throws WxErrorException; /** - * 删除卡券接口 + * 删除卡券接口. + * * @param cardId * @return * @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 bdd1990440..d96b9752d0 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 @@ -2,20 +2,20 @@ import com.google.gson.*; import com.google.gson.reflect.TypeToken; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.bean.WxCardApiSignature; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.RandomUtils; -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.*; import me.chanjar.weixin.mp.enums.TicketType; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.Arrays; import java.util.concurrent.locks.Lock; @@ -25,46 +25,22 @@ * * @author BinaryWang */ +@Slf4j +@RequiredArgsConstructor public class WxMpCardServiceImpl implements WxMpCardService { - private final Logger log = LoggerFactory.getLogger(WxMpCardServiceImpl.class); - - private WxMpService wxMpService; - private static final Gson GSON = WxMpGsonBuilder.create(); - - public WxMpCardServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } + private final WxMpService wxMpService; @Override public WxMpService getWxMpService() { return this.wxMpService; } - /** - * 获得卡券api_ticket,不强制刷新卡券api_ticket. - * - * @return 卡券api_ticket - * @see #getCardApiTicket(boolean) - */ @Override public String getCardApiTicket() throws WxErrorException { return getCardApiTicket(false); } - /** - *
-   * 获得卡券api_ticket.
-   * 获得时会检查卡券apiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干
-   *
-   * 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD
-   * .954-.E5.8D.A1.E5.88.B8.E6.89.A9.E5.B1.95.E5.AD.97.E6.AE.B5.E5.8F.8A.E7.AD.BE.E5.90.8D.E7.94
-   * .9F.E6.88.90.E7.AE.97.E6.B3.95
-   * 
- * - * @param forceRefresh 强制刷新 - * @return 卡券api_ticket - */ @Override public String getCardApiTicket(boolean forceRefresh) throws WxErrorException { final TicketType type = TicketType.WX_CARD; @@ -91,32 +67,22 @@ public String getCardApiTicket(boolean forceRefresh) throws WxErrorException { return this.getWxMpService().getWxMpConfigStorage().getTicket(type); } - /** - *
-   * 创建调用卡券api时所需要的签名
-   *
-   * 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD
-   * .954-.E5.8D.A1.E5.88.B8.E6.89.A9.E5.B1.95.E5.AD.97.E6.AE.B5.E5.8F.8A.E7.AD.BE.E5.90.8D.E7.94
-   * .9F.E6.88.90.E7.AE.97.E6.B3.95
-   * 
- * - * @param optionalSignParam 参与签名的参数数组。 - * 可以为下列字段:app_id, card_id, card_type, code, openid, location_id - *
注意:当做wx.chooseCard调用时,必须传入app_id参与签名,否则会造成签名失败导致拉取卡券列表为空 - * @return 卡券Api签名对象 - */ @Override - public WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws - WxErrorException { + public WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws WxErrorException { long timestamp = System.currentTimeMillis() / 1000; String nonceStr = RandomUtils.getRandomStr(); String cardApiTicket = getCardApiTicket(false); - String[] signParam = Arrays.copyOf(optionalSignParam, optionalSignParam.length + 3); - signParam[optionalSignParam.length] = String.valueOf(timestamp); - signParam[optionalSignParam.length + 1] = nonceStr; - signParam[optionalSignParam.length + 2] = cardApiTicket; - String signature = SHA1.gen(signParam); + String[] signParams = Arrays.copyOf(optionalSignParam, optionalSignParam.length + 3); + signParams[optionalSignParam.length] = String.valueOf(timestamp); + signParams[optionalSignParam.length + 1] = nonceStr; + signParams[optionalSignParam.length + 2] = cardApiTicket; + StringBuilder sb = new StringBuilder(); + for (String a : signParams) { + sb.append(a); + } + String signature = DigestUtils.sha1Hex(sb.toString()); + WxCardApiSignature cardApiSignature = new WxCardApiSignature(); cardApiSignature.setTimestamp(timestamp); cardApiSignature.setNonceStr(nonceStr); @@ -124,12 +90,6 @@ public WxCardApiSignature createCardApiSignature(String... optionalSignParam) th return cardApiSignature; } - /** - * 卡券Code解码 - * - * @param encryptCode 加密Code,通过JSSDK的chooseCard接口获得 - * @return 解密后的Code - */ @Override public String decryptCardCode(String encryptCode) throws WxErrorException { JsonObject param = new JsonObject(); @@ -154,26 +114,11 @@ public WxMpCardResult queryCardCode(String cardId, String code, boolean checkCon }.getType()); } - /** - * 卡券Code核销。核销失败会抛出异常 - * - * @param code 单张卡券的唯一标准 - * @return 调用返回的JSON字符串。 - *
可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。 - */ @Override public String consumeCardCode(String code) throws WxErrorException { return consumeCardCode(code, null); } - /** - * 卡券Code核销。核销失败会抛出异常 - * - * @param code 单张卡券的唯一标准 - * @param cardId 当自定义Code卡券时需要传入card_id - * @return 调用返回的JSON字符串。 - *
可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。 - */ @Override public String consumeCardCode(String code, String cardId) throws WxErrorException { JsonObject param = new JsonObject(); @@ -186,19 +131,8 @@ public String consumeCardCode(String code, String cardId) throws WxErrorExceptio return this.wxMpService.post(CARD_CODE_CONSUME, param.toString()); } - /** - * 卡券Mark接口。 - * 开发者在帮助消费者核销卡券之前,必须帮助先将此code(卡券串码)与一个openid绑定(即mark住), - * 才能进一步调用核销接口,否则报错。 - * - * @param code 卡券的code码 - * @param cardId 卡券的ID - * @param openId 用券用户的openid - * @param isMark 是否要mark(占用)这个code,填写true或者false,表示占用或解除占用 - */ @Override - public void markCardCode(String code, String cardId, String openId, boolean isMark) throws - WxErrorException { + public void markCardCode(String code, String cardId, String openId, boolean isMark) throws WxErrorException { JsonObject param = new JsonObject(); param.addProperty("code", code); param.addProperty("card_id", cardId); @@ -210,7 +144,7 @@ public void markCardCode(String code, String cardId, String openId, boolean isMa new TypeToken() { }.getType()); if (!"0".equals(cardResult.getErrorCode())) { - this.log.warn("朋友的券mark失败:{}", cardResult.getErrorMsg()); + log.warn("朋友的券mark失败:{}", cardResult.getErrorMsg()); } } @@ -233,43 +167,26 @@ public String getCardDetail(String cardId) throws WxErrorException { return responseContent; } - /** - * 添加测试白名单. - * - * @param openid 用户的openid - */ @Override 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; + return this.wxMpService.post(CARD_TEST_WHITELIST, GSON.toJson(jsonObject)); } @Override public WxMpCardCreateResult createCard(WxMpCardCreateMessage cardCreateMessage) throws WxErrorException { - String response = this.wxMpService.post(CARD_CREATE, GSON.toJson(cardCreateMessage)); return WxMpCardCreateResult.fromJson(response); } - /** - * 创建卡券二维码. - */ @Override public WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr) throws WxErrorException { return createQrcodeCard(cardId, outerStr, 0); } - /** - * 创建卡券二维码. - * - * @param cardId 卡券编号 - * @param outerStr 二维码标识 - * @param expiresIn 失效时间,单位秒,不填默认365天 - */ @Override public WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr, int expiresIn) throws WxErrorException { JsonObject jsonObject = new JsonObject(); @@ -286,23 +203,12 @@ public WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerSt return WxMpCardQrcodeCreateResult.fromJson(this.wxMpService.post(CARD_QRCODE_CREATE, GSON.toJson(jsonObject))); } - /** - * 创建卡券货架接口. - */ @Override public WxMpCardLandingPageCreateResult createLandingPage(WxMpCardLandingPageCreateRequest request) throws WxErrorException { String response = this.wxMpService.post(CARD_LANDING_PAGE_CREATE, 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 设置为失效的原因 - */ @Override public String unavailableCardCode(String cardId, String code, String reason) throws WxErrorException { if (StringUtils.isAnyBlank(cardId, code, reason)) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardDeleteResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardDeleteResult.java index 3dcbc3534c..8eedbebf60 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardDeleteResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/WxMpCardDeleteResult.java @@ -3,11 +3,13 @@ import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; /** - * @description 删除卡券结果 - * @author: fanxl - * @date: 2019/1/22 0022 10:24 + * 删除卡券结果. + * + * @author fanxl + * @date 2019/1/22 0022 10:24 */ public class WxMpCardDeleteResult extends BaseWxMpCardResult { + private static final long serialVersionUID = -4367717540650523290L; public static WxMpCardDeleteResult fromJson(String json) { return WxMpGsonBuilder.create().fromJson(json, WxMpCardDeleteResult.class); From 60ebb5495819e4ea9b510c7e3ca611245d74a726 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 2 Jun 2019 12:58:43 +0800 Subject: [PATCH 08/74] =?UTF-8?q?#1059=20=E5=BE=AE=E4=BF=A1=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E8=AF=81=E4=B9=A6=E5=9C=B0=E5=9D=80=E5=8F=82=E6=95=B0?= =?UTF-8?q?keyPath=E6=94=AF=E6=8C=81=E4=BD=BF=E7=94=A8=E7=BD=91=E7=BB=9C?= =?UTF-8?q?=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../binarywang/wxpay/config/WxPayConfig.java | 25 +++++++++++-------- .../wxpay/config/WxPayConfigTest.java | 14 ++++++----- 2 files changed, 23 insertions(+), 16 deletions(-) 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 f8d915f8a8..93b3b700d0 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 @@ -1,19 +1,15 @@ package com.github.binarywang.wxpay.config; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.security.KeyStore; -import javax.net.ssl.SSLContext; - +import com.github.binarywang.wxpay.exception.WxPayException; +import lombok.Data; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.http.ssl.SSLContexts; -import com.github.binarywang.wxpay.exception.WxPayException; -import lombok.Data; +import javax.net.ssl.SSLContext; +import java.io.*; +import java.net.URL; +import java.security.KeyStore; /** * 微信支付配置 @@ -131,6 +127,15 @@ public SSLContext initSSLContext() throws WxPayException { if (inputStream == null) { throw new WxPayException(fileNotFoundMsg); } + } else if (this.getKeyPath().startsWith("http://") || this.getKeyPath().startsWith("https://")) { + try { + inputStream = new URL(this.keyPath).openStream(); + if (inputStream == null) { + throw new WxPayException(fileNotFoundMsg); + } + } catch (IOException e) { + throw new WxPayException(fileNotFoundMsg, e); + } } else { try { File file = new File(this.getKeyPath()); 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 3edc2c3268..9d3c13da42 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,16 +14,18 @@ public class WxPayConfigTest { private WxPayConfig payConfig = new WxPayConfig(); - /** - * Test init ssl context. - * - * @throws Exception the exception - */ @Test - public void testInitSSLContext() throws Exception { + public void testInitSSLContext_classpath() throws Exception { payConfig.setMchId("123"); payConfig.setKeyPath("classpath:/abc.p12"); payConfig.initSSLContext(); } + @Test + public void testInitSSLContext_http() throws Exception { + payConfig.setMchId("123"); + payConfig.setKeyPath("https://www.baidu.com"); + payConfig.initSSLContext(); + } + } From 6b08dc881e228031e4bf9bf17c43928d4610afa1 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 2 Jun 2019 14:38:21 +0800 Subject: [PATCH 09/74] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2f01901cf5..60c4d53e7c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ language: java jdk: - oraclejdk8 -script: "./mvnw clean package -DskipTests=true" +script: "./mvnw clean package -DskipTests=true -Dcheckstyle.skip=true" #script: # - mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar From 97e88bd99ddb961a0aab191c93059bf066a17801 Mon Sep 17 00:00:00 2001 From: crazycode Date: Sun, 2 Jun 2019 14:40:51 +0800 Subject: [PATCH 10/74] =?UTF-8?q?#1065=20=E6=94=AF=E6=8C=81=E7=A7=81?= =?UTF-8?q?=E6=9C=89=E5=8C=96=E9=83=A8=E7=BD=B2=E7=89=88=E6=9C=AC=E7=9A=84?= =?UTF-8?q?=E4=BC=81=E4=B8=9A=E5=BE=AE=E4=BF=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 通过 wxCpConfigStorage.setBaseApiUrl("http://local_server:port"); 设置私有化部署的企业微信服务地址. 默认值是 https://qyapi.weixin.qq.com , 如果使用默认值,则不需要调用 setBaseApiUrl(baseUrl). --- .../weixin/cp/api/WxCpAgentService.java | 6 +- .../weixin/cp/api/WxCpChatService.java | 8 +- .../weixin/cp/api/WxCpDepartmentService.java | 12 +- .../weixin/cp/api/WxCpMediaService.java | 14 +- .../weixin/cp/api/WxCpMenuService.java | 6 +- .../weixin/cp/api/WxCpOAuth2Service.java | 4 +- .../chanjar/weixin/cp/api/WxCpOaService.java | 8 +- .../me/chanjar/weixin/cp/api/WxCpService.java | 18 +- .../chanjar/weixin/cp/api/WxCpTagService.java | 14 +- .../weixin/cp/api/WxCpTaskCardService.java | 2 +- .../chanjar/weixin/cp/api/WxCpTpService.java | 8 +- .../weixin/cp/api/WxCpUserService.java | 30 +- .../cp/api/impl/BaseWxCpServiceImpl.java | 46 +- .../cp/api/impl/BaseWxCpTpServiceImpl.java | 488 +++++++++--------- .../cp/api/impl/WxCpAgentServiceImpl.java | 13 +- .../cp/api/impl/WxCpChatServiceImpl.java | 8 +- .../api/impl/WxCpDepartmentServiceImpl.java | 14 +- .../cp/api/impl/WxCpMediaServiceImpl.java | 19 +- .../cp/api/impl/WxCpMenuServiceImpl.java | 8 +- .../cp/api/impl/WxCpOAuth2ServiceImpl.java | 4 +- .../weixin/cp/api/impl/WxCpOaServiceImpl.java | 8 +- .../impl/WxCpServiceApacheHttpClientImpl.java | 3 +- .../cp/api/impl/WxCpServiceJoddHttpImpl.java | 8 +- .../cp/api/impl/WxCpServiceOkHttpImpl.java | 9 +- .../cp/api/impl/WxCpTagServiceImpl.java | 30 +- .../cp/api/impl/WxCpTaskCardServiceImpl.java | 4 +- .../WxCpTpServiceApacheHttpClientImpl.java | 2 +- .../cp/api/impl/WxCpUserServiceImpl.java | 39 +- .../weixin/cp/config/WxCpConfigStorage.java | 16 + .../cp/config/WxCpInMemoryConfigStorage.java | 15 + .../cp/config/WxCpJedisConfigStorage.java | 15 + .../weixin/cp/config/WxCpTpConfigStorage.java | 160 +++--- .../config/WxCpTpInMemoryConfigStorage.java | 475 ++++++++--------- .../cp/api/impl/WxCpAgentServiceImplTest.java | 4 +- .../cp/api/impl/WxCpTagServiceImplTest.java | 3 +- 35 files changed, 824 insertions(+), 697 deletions(-) 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 30214a478f..7dad7b6c76 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 @@ -15,9 +15,9 @@ * @author huansinho */ public interface WxCpAgentService { - String GET_AGENT = "https://qyapi.weixin.qq.com/cgi-bin/agent/get?agentid=%d"; - String AGENT_SET = "https://qyapi.weixin.qq.com/cgi-bin/agent/set"; - String AGENT_LIST = "https://qyapi.weixin.qq.com/cgi-bin/agent/list"; + String GET_AGENT = "/cgi-bin/agent/get?agentid=%d"; + String AGENT_SET = "/cgi-bin/agent/set"; + String AGENT_LIST = "/cgi-bin/agent/list"; /** *
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpChatService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpChatService.java
index bbfc0fdd48..58ab329f01 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpChatService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpChatService.java
@@ -12,10 +12,10 @@
  * @author gaigeshen
  */
 public interface WxCpChatService {
-  String APPCHAT_CREATE = "https://qyapi.weixin.qq.com/cgi-bin/appchat/create";
-  String APPCHAT_UPDATE = "https://qyapi.weixin.qq.com/cgi-bin/appchat/update";
-  String APPCHAT_GET_CHATID = "https://qyapi.weixin.qq.com/cgi-bin/appchat/get?chatid=";
-  String APPCHAT_SEND = "https://qyapi.weixin.qq.com/cgi-bin/appchat/send";
+  String APPCHAT_CREATE = "/cgi-bin/appchat/create";
+  String APPCHAT_UPDATE = "/cgi-bin/appchat/update";
+  String APPCHAT_GET_CHATID = "/cgi-bin/appchat/get?chatid=";
+  String APPCHAT_SEND = "/cgi-bin/appchat/send";
 
   @Deprecated
   String chatCreate(String name, String owner, List users, String chatId) throws WxErrorException;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java
index 3f80d693ad..8aa7ca353a 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java
@@ -1,10 +1,10 @@
 package me.chanjar.weixin.cp.api;
 
-import java.util.List;
-
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.cp.bean.WxCpDepart;
 
+import java.util.List;
+
 /**
  * 
  *  部门管理接口
@@ -14,10 +14,10 @@
  * @author Binary Wang
  */
 public interface WxCpDepartmentService {
-  String DEPARTMENT_CREATE = "https://qyapi.weixin.qq.com/cgi-bin/department/create";
-  String DEPARTMENT_UPDATE = "https://qyapi.weixin.qq.com/cgi-bin/department/update";
-  String DEPARTMENT_DELETE = "https://qyapi.weixin.qq.com/cgi-bin/department/delete?id=%d";
-  String DEPARTMENT_LIST = "https://qyapi.weixin.qq.com/cgi-bin/department/list";
+  String DEPARTMENT_CREATE = "/cgi-bin/department/create";
+  String DEPARTMENT_UPDATE = "/cgi-bin/department/update";
+  String DEPARTMENT_DELETE = "/cgi-bin/department/delete?id=%d";
+  String DEPARTMENT_LIST = "/cgi-bin/department/list";
 
   /**
    * 
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 31ce6b5991..67c67ec625 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
@@ -1,12 +1,12 @@
 package me.chanjar.weixin.cp.api;
 
+import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
+import me.chanjar.weixin.common.error.WxErrorException;
+
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 
-import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
-import me.chanjar.weixin.common.error.WxErrorException;
-
 /**
  * 
  *  媒体管理接口.
@@ -16,10 +16,10 @@
  * @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";
-  String JSSDK_MEDIA_GET_URL = "https://qyapi.weixin.qq.com/cgi-bin/media/get/jssdk";
+  String MEDIA_GET_URL = "/cgi-bin/media/get";
+  String MEDIA_UPLOAD_URL = "/cgi-bin/media/upload?type=";
+  String IMG_UPLOAD_URL = "/cgi-bin/media/uploadimg";
+  String JSSDK_MEDIA_GET_URL = "/cgi-bin/media/get/jssdk";
 
   /**
    * 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java
index be7b4b7e55..7c0a01e595 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java
@@ -12,9 +12,9 @@
  * @author Binary Wang
  */
 public interface WxCpMenuService {
-  String MENU_CREATE = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?agentid=%d";
-  String MENU_DELETE = "https://qyapi.weixin.qq.com/cgi-bin/menu/delete?agentid=%d";
-  String MENU_GET = "https://qyapi.weixin.qq.com/cgi-bin/menu/get?agentid=%d";
+  String MENU_CREATE = "/cgi-bin/menu/create?agentid=%d";
+  String MENU_DELETE = "/cgi-bin/menu/delete?agentid=%d";
+  String MENU_GET = "/cgi-bin/menu/get?agentid=%d";
 
   /**
    * 
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 c6d9063fbb..39d2163e7b 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
@@ -13,8 +13,8 @@
  * @author Binary Wang
  */
 public interface WxCpOAuth2Service {
-  String URL_GET_USER_INFO = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?code=%s&agentid=%d";
-  String URL_GET_USER_DETAIL = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserdetail";
+  String URL_GET_USER_INFO = "/cgi-bin/user/getuserinfo?code=%s&agentid=%d";
+  String URL_GET_USER_DETAIL = "/cgi-bin/user/getuserdetail";
   String URL_OAUTH_2_AUTHORIZE = "https://open.weixin.qq.com/connect/oauth2/authorize";
 
   /**
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaService.java
index 26922c0eee..5cca9e7788 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaService.java
@@ -16,10 +16,10 @@
  * @date 2019-04-06 10:52
  */
 public interface WxCpOaService {
-  String GET_CHECKIN_DATA = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckindata";
-  String GET_CHECKIN_OPTION = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckinoption";
-  String GET_APPROVAL_DATA = "https://qyapi.weixin.qq.com/cgi-bin/corp/getapprovaldata";
-  String GET_DIAL_RECORD = "https://qyapi.weixin.qq.com/cgi-bin/dial/get_dial_record";
+  String GET_CHECKIN_DATA = "/cgi-bin/checkin/getcheckindata";
+  String GET_CHECKIN_OPTION = "/cgi-bin/checkin/getcheckinoption";
+  String GET_APPROVAL_DATA = "/cgi-bin/corp/getapprovaldata";
+  String GET_DIAL_RECORD = "/cgi-bin/dial/get_dial_record";
 
   /**
    * 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java
index 13d2e9dc4a..12ae987b1b 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java
@@ -17,15 +17,15 @@
  * @author chanjaster
  */
 public interface WxCpService {
-  String GET_JSAPI_TICKET = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket";
-  String GET_AGENT_CONFIG_TICKET = "https://qyapi.weixin.qq.com/cgi-bin/ticket/get?&type=agent_config";
-  String MESSAGE_SEND = "https://qyapi.weixin.qq.com/cgi-bin/message/send";
-  String GET_CALLBACK_IP = "https://qyapi.weixin.qq.com/cgi-bin/getcallbackip";
-  String BATCH_REPLACE_PARTY = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceparty";
-  String BATCH_REPLACE_USER = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceuser";
-  String BATCH_GET_RESULT = "https://qyapi.weixin.qq.com/cgi-bin/batch/getresult?jobid=";
-  String JSCODE_TO_SESSION_URL = "https://qyapi.weixin.qq.com/cgi-bin/miniprogram/jscode2session";
-  String GET_TOKEN = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?&corpid=%s&corpsecret=%s";
+  String GET_JSAPI_TICKET = "/cgi-bin/get_jsapi_ticket";
+  String GET_AGENT_CONFIG_TICKET = "/cgi-bin/ticket/get?&type=agent_config";
+  String MESSAGE_SEND = "/cgi-bin/message/send";
+  String GET_CALLBACK_IP = "/cgi-bin/getcallbackip";
+  String BATCH_REPLACE_PARTY = "/cgi-bin/batch/replaceparty";
+  String BATCH_REPLACE_USER = "/cgi-bin/batch/replaceuser";
+  String BATCH_GET_RESULT = "/cgi-bin/batch/getresult?jobid=";
+  String JSCODE_TO_SESSION_URL = "/cgi-bin/miniprogram/jscode2session";
+  String GET_TOKEN = "/cgi-bin/gettoken?&corpid=%s&corpsecret=%s";
 
   /**
    * 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java
index a570a80b10..ee1b526d64 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java
@@ -17,13 +17,13 @@
  * @author Binary Wang
  */
 public interface WxCpTagService {
-  String TAG_CREATE = "https://qyapi.weixin.qq.com/cgi-bin/tag/create";
-  String TAG_UPDATE = "https://qyapi.weixin.qq.com/cgi-bin/tag/update";
-  String TAG_DELETE = "https://qyapi.weixin.qq.com/cgi-bin/tag/delete?tagid=%s";
-  String TAG_LIST = "https://qyapi.weixin.qq.com/cgi-bin/tag/list";
-  String TAG_GET = "https://qyapi.weixin.qq.com/cgi-bin/tag/get?tagid=%s";
-  String TAG_ADDTAGUSERS = "https://qyapi.weixin.qq.com/cgi-bin/tag/addtagusers";
-  String TAG_DELTAGUSERS = "https://qyapi.weixin.qq.com/cgi-bin/tag/deltagusers";
+  String TAG_CREATE = "/cgi-bin/tag/create";
+  String TAG_UPDATE = "/cgi-bin/tag/update";
+  String TAG_DELETE = "/cgi-bin/tag/delete?tagid=%s";
+  String TAG_LIST = "/cgi-bin/tag/list";
+  String TAG_GET = "/cgi-bin/tag/get?tagid=%s";
+  String TAG_ADDTAGUSERS = "/cgi-bin/tag/addtagusers";
+  String TAG_DELTAGUSERS = "/cgi-bin/tag/deltagusers";
 
   /**
    * 创建标签.
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTaskCardService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTaskCardService.java
index 1e1077014f..b6ebdc1202 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTaskCardService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTaskCardService.java
@@ -14,7 +14,7 @@
  * @date 2019-05-16
  */
 public interface WxCpTaskCardService {
-  String MESSAGE_UPDATE_TASKCARD = "https://qyapi.weixin.qq.com/cgi-bin/message/update_taskcard";
+  String MESSAGE_UPDATE_TASKCARD = "/cgi-bin/message/update_taskcard";
 
   /**
    * 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java
index 6e0d63fb2c..6c52bcfde6 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java
@@ -15,10 +15,10 @@
  * @author zhenjun cai
  */
 public interface WxCpTpService {
-  String JSCODE_TO_SESSION_URL = "https://qyapi.weixin.qq.com/cgi-bin/service/miniprogram/jscode2session";
-  String GET_CORP_TOKEN = "https://qyapi.weixin.qq.com/cgi-bin/service/get_corp_token";
-  String GET_PERMANENT_CODE = "https://qyapi.weixin.qq.com/cgi-bin/service/get_permanent_code";
-  String GET_SUITE_TOKEN = "https://qyapi.weixin.qq.com/cgi-bin/service/get_suite_token";
+  String JSCODE_TO_SESSION_URL = "/cgi-bin/service/miniprogram/jscode2session";
+  String GET_CORP_TOKEN = "/cgi-bin/service/get_corp_token";
+  String GET_PERMANENT_CODE = "/cgi-bin/service/get_permanent_code";
+  String GET_SUITE_TOKEN = "/cgi-bin/service/get_suite_token";
 
   /**
    * 
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 091c687595..4289ae94c7 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,13 +1,13 @@
 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 me.chanjar.weixin.cp.bean.WxCpUserExternalContactInfo;
 
+import java.util.List;
+import java.util.Map;
+
 /**
  * 
  * 用户管理接口
@@ -17,18 +17,18 @@
  * @author Binary Wang
  */
 public interface WxCpUserService {
-  String URL_AUTHENTICATE = "https://qyapi.weixin.qq.com/cgi-bin/user/authsucc?userid=";
-  String URL_USER_CREATE = "https://qyapi.weixin.qq.com/cgi-bin/user/create";
-  String URL_USER_UPDATE = "https://qyapi.weixin.qq.com/cgi-bin/user/update";
-  String URL_USER_DELETE = "https://qyapi.weixin.qq.com/cgi-bin/user/delete?userid=";
-  String URL_USER_BATCH_DELETE = "https://qyapi.weixin.qq.com/cgi-bin/user/batchdelete";
-  String URL_USER_GET = "https://qyapi.weixin.qq.com/cgi-bin/user/get?userid=";
-  String URL_USER_LIST = "https://qyapi.weixin.qq.com/cgi-bin/user/list?department_id=";
-  String URL_USER_SIMPLE_LIST = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?department_id=";
-  String URL_BATCH_INVITE = "https://qyapi.weixin.qq.com/cgi-bin/batch/invite";
-  String URL_CONVERT_TO_OPENID = "https://qyapi.weixin.qq.com/cgi-bin/user/convert_to_openid";
-  String URL_CONVERT_TO_USERID = "https://qyapi.weixin.qq.com/cgi-bin/user/convert_to_userid";
-  String URL_GET_EXTERNAL_CONTACT = "https://qyapi.weixin.qq.com/cgi-bin/crm/get_external_contact?external_userid=";
+  String URL_AUTHENTICATE = "/cgi-bin/user/authsucc?userid=";
+  String URL_USER_CREATE = "/cgi-bin/user/create";
+  String URL_USER_UPDATE = "/cgi-bin/user/update";
+  String URL_USER_DELETE = "/cgi-bin/user/delete?userid=";
+  String URL_USER_BATCH_DELETE = "/cgi-bin/user/batchdelete";
+  String URL_USER_GET = "/cgi-bin/user/get?userid=";
+  String URL_USER_LIST = "/cgi-bin/user/list?department_id=";
+  String URL_USER_SIMPLE_LIST = "/cgi-bin/user/simplelist?department_id=";
+  String URL_BATCH_INVITE = "/cgi-bin/batch/invite";
+  String URL_CONVERT_TO_OPENID = "/cgi-bin/user/convert_to_openid";
+  String URL_CONVERT_TO_USERID = "/cgi-bin/user/convert_to_userid";
+  String URL_GET_EXTERNAL_CONTACT = "/cgi-bin/crm/get_external_contact?external_userid=";
 
   /**
    * 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java
index d9c88b47a5..e0bab1d90e 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java
@@ -18,7 +18,17 @@
 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.cp.api.*;
+import me.chanjar.weixin.cp.api.WxCpAgentService;
+import me.chanjar.weixin.cp.api.WxCpChatService;
+import me.chanjar.weixin.cp.api.WxCpDepartmentService;
+import me.chanjar.weixin.cp.api.WxCpMediaService;
+import me.chanjar.weixin.cp.api.WxCpMenuService;
+import me.chanjar.weixin.cp.api.WxCpOAuth2Service;
+import me.chanjar.weixin.cp.api.WxCpOaService;
+import me.chanjar.weixin.cp.api.WxCpService;
+import me.chanjar.weixin.cp.api.WxCpTagService;
+import me.chanjar.weixin.cp.api.WxCpTaskCardService;
+import me.chanjar.weixin.cp.api.WxCpUserService;
 import me.chanjar.weixin.cp.bean.WxCpMaJsCode2SessionResult;
 import me.chanjar.weixin.cp.bean.WxCpMessage;
 import me.chanjar.weixin.cp.bean.WxCpMessageSendResult;
@@ -37,16 +47,16 @@
 public abstract class BaseWxCpServiceImpl implements WxCpService, RequestHttp {
   protected final Logger log = LoggerFactory.getLogger(this.getClass());
 
-  private WxCpUserService userService = new WxCpUserServiceImpl(this);
-  private WxCpChatService chatService = new WxCpChatServiceImpl(this);
+  private WxCpUserService       userService       = new WxCpUserServiceImpl(this);
+  private WxCpChatService       chatService       = new WxCpChatServiceImpl(this);
   private WxCpDepartmentService departmentService = new WxCpDepartmentServiceImpl(this);
-  private WxCpMediaService mediaService = new WxCpMediaServiceImpl(this);
-  private WxCpMenuService menuService = new WxCpMenuServiceImpl(this);
-  private WxCpOAuth2Service oauth2Service = new WxCpOAuth2ServiceImpl(this);
-  private WxCpTagService tagService = new WxCpTagServiceImpl(this);
-  private WxCpAgentService agentService = new WxCpAgentServiceImpl(this);
-  private WxCpOaService oaService = new WxCpOaServiceImpl(this);
-  private WxCpTaskCardService taskCardService = new WxCpTaskCardServiceImpl(this);
+  private WxCpMediaService      mediaService      = new WxCpMediaServiceImpl(this);
+  private WxCpMenuService       menuService       = new WxCpMenuServiceImpl(this);
+  private WxCpOAuth2Service     oauth2Service     = new WxCpOAuth2ServiceImpl(this);
+  private WxCpTagService        tagService        = new WxCpTagServiceImpl(this);
+  private WxCpAgentService      agentService      = new WxCpAgentServiceImpl(this);
+  private WxCpOaService         oaService         = new WxCpOaServiceImpl(this);
+  private WxCpTaskCardService   taskCardService   = new WxCpTaskCardServiceImpl(this);
 
   /**
    * 全局的是否正在刷新access token的锁
@@ -104,7 +114,7 @@ public String getAgentJsapiTicket(boolean forceRefresh) throws WxErrorException
     if (this.configStorage.isAgentJsapiTicketExpired()) {
       synchronized (this.globalAgentJsapiTicketRefreshLock) {
         if (this.configStorage.isAgentJsapiTicketExpired()) {
-          String responseContent = this.get(WxCpService.GET_AGENT_CONFIG_TICKET, null);
+          String responseContent = this.get(this.configStorage.getApiUrl(WxCpService.GET_AGENT_CONFIG_TICKET), null);
           JsonObject jsonObject = new JsonParser().parse(responseContent).getAsJsonObject();
           this.configStorage.updateAgentJsapiTicket(jsonObject.get("ticket").getAsString(),
             jsonObject.get("expires_in").getAsInt());
@@ -129,7 +139,7 @@ public String getJsapiTicket(boolean forceRefresh) throws WxErrorException {
     if (this.configStorage.isJsapiTicketExpired()) {
       synchronized (this.globalJsapiTicketRefreshLock) {
         if (this.configStorage.isJsapiTicketExpired()) {
-          String responseContent = this.get(WxCpService.GET_JSAPI_TICKET, null);
+          String responseContent = this.get(this.configStorage.getApiUrl(WxCpService.GET_JSAPI_TICKET), null);
           JsonObject tmpJsonObject = new JsonParser().parse(responseContent).getAsJsonObject();
           this.configStorage.updateJsapiTicket(tmpJsonObject.get("ticket").getAsString(),
             tmpJsonObject.get("expires_in").getAsInt());
@@ -170,7 +180,7 @@ public WxCpMessageSendResult messageSend(WxCpMessage message) throws WxErrorExce
       message.setAgentId(this.getWxCpConfigStorage().getAgentId());
     }
 
-    return WxCpMessageSendResult.fromJson(this.post(WxCpService.MESSAGE_SEND, message.toJson()));
+    return WxCpMessageSendResult.fromJson(this.post(this.configStorage.getApiUrl(WxCpService.MESSAGE_SEND), message.toJson()));
   }
 
   @Override
@@ -179,13 +189,13 @@ public WxCpMaJsCode2SessionResult jsCode2Session(String jsCode) throws WxErrorEx
     params.put("js_code", jsCode);
     params.put("grant_type", "authorization_code");
 
-    String result = this.get(JSCODE_TO_SESSION_URL, Joiner.on("&").withKeyValueSeparator("=").join(params));
+    String result = this.get(this.configStorage.getApiUrl(JSCODE_TO_SESSION_URL), Joiner.on("&").withKeyValueSeparator("=").join(params));
     return WxCpMaJsCode2SessionResult.fromJson(result);
   }
 
   @Override
   public String[] getCallbackIp() throws WxErrorException {
-    String responseContent = get(WxCpService.GET_CALLBACK_IP, null);
+    String responseContent = get(this.configStorage.getApiUrl(WxCpService.GET_CALLBACK_IP), null);
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     JsonArray jsonArray = tmpJsonElement.getAsJsonObject().get("ip_list").getAsJsonArray();
     String[] ips = new String[jsonArray.size()];
@@ -329,19 +339,19 @@ public WxSessionManager getSessionManager() {
   public String replaceParty(String mediaId) throws WxErrorException {
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("media_id", mediaId);
-    return post(WxCpService.BATCH_REPLACE_PARTY, jsonObject.toString());
+    return post(this.configStorage.getApiUrl(WxCpService.BATCH_REPLACE_PARTY), jsonObject.toString());
   }
 
   @Override
   public String replaceUser(String mediaId) throws WxErrorException {
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("media_id", mediaId);
-    return post(WxCpService.BATCH_REPLACE_USER, jsonObject.toString());
+    return post(this.configStorage.getApiUrl(WxCpService.BATCH_REPLACE_USER), jsonObject.toString());
   }
 
   @Override
   public String getTaskResult(String joinId) throws WxErrorException {
-    String url = WxCpService.BATCH_GET_RESULT + joinId;
+    String url = this.configStorage.getApiUrl(WxCpService.BATCH_GET_RESULT + joinId);
     return get(url, null);
   }
 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImpl.java
index 837c355e4d..f3714516cf 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImpl.java
@@ -1,244 +1,244 @@
-package me.chanjar.weixin.cp.api.impl;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Joiner;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
-
-import me.chanjar.weixin.common.WxType;
-import me.chanjar.weixin.common.bean.WxAccessToken;
-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.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.cp.api.WxCpService;
-import me.chanjar.weixin.cp.api.WxCpTpService;
-import me.chanjar.weixin.cp.bean.WxCpMaJsCode2SessionResult;
-import me.chanjar.weixin.cp.bean.WxCpTpCorp;
-import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
-
-/**
- * @author zhenjun cai
- */
-public abstract class BaseWxCpTpServiceImpl implements WxCpTpService, RequestHttp {
-  protected final Logger log = LoggerFactory.getLogger(this.getClass());
-
-  /**
-   * 全局的是否正在刷新access token的锁
-   */
-  protected final Object globalSuiteAccessTokenRefreshLock = new Object();
-
-  /**
-   * 全局的是否正在刷新jsapi_ticket的锁
-   */
-  protected final Object globalSuiteTicketRefreshLock = new Object();
-
-
-  protected WxCpTpConfigStorage configStorage;
-
-
-  /**
-   * 临时文件目录
-   */
-  private File tmpDirFile;
-  private int retrySleepMillis = 1000;
-  private int maxRetryTimes = 5;
-
-  @Override
-  public boolean checkSignature(String msgSignature, String timestamp, String nonce, String data) {
-    try {
-      return SHA1.gen(this.configStorage.getToken(), timestamp, nonce, data)
-        .equals(msgSignature);
-    } catch (Exception e) {
-      this.log.error("Checking signature failed, and the reason is :" + e.getMessage());
-      return false;
-    }
-  }
-
-  @Override
-  public String getSuiteAccessToken() throws WxErrorException {
-    return getSuiteAccessToken(false);
-  }
-
-  @Override
-  public String getSuiteTicket() throws WxErrorException {
-    return getSuiteTicket(false);
-  }
-
-  @Override
-  public String getSuiteTicket(boolean forceRefresh) throws WxErrorException {
-//	  suite ticket由微信服务器推送,不能强制刷新
-//    if (forceRefresh) {
-//      this.configStorage.expireSuiteTicket();
-//    }
-
-	if (this.configStorage.isSuiteTicketExpired()) {
-//	   本地suite ticket 不存在或者过期	
-	  WxError wxError = WxError.fromJson("{\"errcode\":40085, \"errmsg\":\"invaild suite ticket\"}", WxType.CP);
-	  throw new WxErrorException(wxError);
-	}
-    return this.configStorage.getSuiteTicket();
-  }
-
-
-  @Override
-  public WxCpMaJsCode2SessionResult jsCode2Session(String jsCode) throws WxErrorException {
-    Map params = new HashMap<>(2);
-    params.put("js_code", jsCode);
-    params.put("grant_type", "authorization_code");
-
-    String result = this.get(JSCODE_TO_SESSION_URL, Joiner.on("&").withKeyValueSeparator("=").join(params));
-    return WxCpMaJsCode2SessionResult.fromJson(result);
-  }
-
-
-  @Override
-  public WxAccessToken getCorpToken(String authCorpid, String permanentCode) throws WxErrorException {
-	JsonObject jsonObject = new JsonObject();
-	jsonObject.addProperty("auth_corpid", authCorpid);
-	jsonObject.addProperty("permanent_code", permanentCode);
-	String result = post(GET_CORP_TOKEN, jsonObject.toString());
-	
-	return WxAccessToken.fromJson(result);
-  }
-  
-
-  @Override
-  public WxCpTpCorp getPermanentCode(String authCode) throws WxErrorException {
-    JsonObject jsonObject = new JsonObject();
-    jsonObject.addProperty("auth_code", authCode);
-
-    String result = post(GET_PERMANENT_CODE, jsonObject.toString());
-    jsonObject = new JsonParser().parse(result).getAsJsonObject();
-    WxCpTpCorp wxCpTpCorp = WxCpTpCorp.fromJson(jsonObject.get("auth_corp_info").getAsString());
-    wxCpTpCorp.setPermanentCode(jsonObject.get("permanent_code").getAsString());
-    return wxCpTpCorp;
-  }
-
-  @Override
-  public String get(String url, String queryParam) throws WxErrorException {
-    return execute(SimpleGetRequestExecutor.create(this), url, queryParam);
-  }
-
-  @Override
-  public String post(String url, String postData) throws WxErrorException {
-    return execute(SimplePostRequestExecutor.create(this), url, postData);
-  }
-
-  /**
-   * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求.
-   */
-  @Override
-  public  T execute(RequestExecutor executor, String uri, E data) throws WxErrorException {
-    int retryTimes = 0;
-    do {
-      try {
-        return this.executeInternal(executor, uri, data);
-      } catch (WxErrorException e) {
-        if (retryTimes + 1 > this.maxRetryTimes) {
-          this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
-          //最后一次重试失败后,直接抛出异常,不再等待
-          throw new RuntimeException("微信服务端异常,超出重试次数");
-        }
-
-        WxError error = e.getError();
-        /*
-         * -1 系统繁忙, 1000ms后重试
-         */
-        if (error.getErrorCode() == -1) {
-          int sleepMillis = this.retrySleepMillis * (1 << retryTimes);
-          try {
-            this.log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
-            Thread.sleep(sleepMillis);
-          } catch (InterruptedException e1) {
-            Thread.currentThread().interrupt();
-          }
-        } else {
-          throw e;
-        }
-      }
-    } while (retryTimes++ < this.maxRetryTimes);
-
-    this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
-    throw new RuntimeException("微信服务端异常,超出重试次数");
-  }
-
-  protected  T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException {
-    E dataForLog = DataUtils.handleDataWithSecret(data);
-
-    if (uri.contains("suite_access_token=")) {
-      throw new IllegalArgumentException("uri参数中不允许有suite_access_token: " + uri);
-    }
-    String suiteAccessToken = getSuiteAccessToken(false);
-
-    String uriWithAccessToken = uri + (uri.contains("?") ? "&" : "?") + "suite_access_token=" + suiteAccessToken;
-
-    try {
-      T result = executor.execute(uriWithAccessToken, data);
-      this.log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result);
-      return result;
-    } catch (WxErrorException e) {
-      WxError error = e.getError();
-      /*
-       * 发生以下情况时尝试刷新suite_access_token
-       * 42009 suite_access_token已过期
-       */
-      if (error.getErrorCode() == 42009) {
-        // 强制设置wxCpTpConfigStorage它的suite access token过期了,这样在下一次请求里就会刷新suite access token
-        this.configStorage.expireSuiteAccessToken();
-        return execute(executor, uri, data);
-      }
-
-      if (error.getErrorCode() != 0) {
-        this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error);
-        throw new WxErrorException(error, e);
-      }
-      return null;
-    } catch (IOException e) {
-      this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage());
-      throw new RuntimeException(e);
-    }
-  }
-
-  @Override
-  public void setWxCpTpConfigStorage(WxCpTpConfigStorage wxConfigProvider) {
-    this.configStorage = wxConfigProvider;
-    this.initHttp();
-  }
-
-  @Override
-  public void setRetrySleepMillis(int retrySleepMillis) {
-    this.retrySleepMillis = retrySleepMillis;
-  }
-
-
-  @Override
-  public void setMaxRetryTimes(int maxRetryTimes) {
-    this.maxRetryTimes = maxRetryTimes;
-  }
-
-  public File getTmpDirFile() {
-    return this.tmpDirFile;
-  }
-
-  public void setTmpDirFile(File tmpDirFile) {
-    this.tmpDirFile = tmpDirFile;
-  }
-
-  @Override
-  public RequestHttp getRequestHttp() {
-    return this;
-  }
-
-}
+package me.chanjar.weixin.cp.api.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Joiner;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+import me.chanjar.weixin.common.WxType;
+import me.chanjar.weixin.common.bean.WxAccessToken;
+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.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.cp.api.WxCpService;
+import me.chanjar.weixin.cp.api.WxCpTpService;
+import me.chanjar.weixin.cp.bean.WxCpMaJsCode2SessionResult;
+import me.chanjar.weixin.cp.bean.WxCpTpCorp;
+import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
+
+/**
+ * @author zhenjun cai
+ */
+public abstract class BaseWxCpTpServiceImpl implements WxCpTpService, RequestHttp {
+  protected final Logger log = LoggerFactory.getLogger(this.getClass());
+
+  /**
+   * 全局的是否正在刷新access token的锁
+   */
+  protected final Object globalSuiteAccessTokenRefreshLock = new Object();
+
+  /**
+   * 全局的是否正在刷新jsapi_ticket的锁
+   */
+  protected final Object globalSuiteTicketRefreshLock = new Object();
+
+
+  protected WxCpTpConfigStorage configStorage;
+
+
+  /**
+   * 临时文件目录
+   */
+  private File tmpDirFile;
+  private int retrySleepMillis = 1000;
+  private int maxRetryTimes = 5;
+
+  @Override
+  public boolean checkSignature(String msgSignature, String timestamp, String nonce, String data) {
+    try {
+      return SHA1.gen(this.configStorage.getToken(), timestamp, nonce, data)
+        .equals(msgSignature);
+    } catch (Exception e) {
+      this.log.error("Checking signature failed, and the reason is :" + e.getMessage());
+      return false;
+    }
+  }
+
+  @Override
+  public String getSuiteAccessToken() throws WxErrorException {
+    return getSuiteAccessToken(false);
+  }
+
+  @Override
+  public String getSuiteTicket() throws WxErrorException {
+    return getSuiteTicket(false);
+  }
+
+  @Override
+  public String getSuiteTicket(boolean forceRefresh) throws WxErrorException {
+//	  suite ticket由微信服务器推送,不能强制刷新
+//    if (forceRefresh) {
+//      this.configStorage.expireSuiteTicket();
+//    }
+
+	if (this.configStorage.isSuiteTicketExpired()) {
+//	   本地suite ticket 不存在或者过期	
+	  WxError wxError = WxError.fromJson("{\"errcode\":40085, \"errmsg\":\"invaild suite ticket\"}", WxType.CP);
+	  throw new WxErrorException(wxError);
+	}
+    return this.configStorage.getSuiteTicket();
+  }
+
+
+  @Override
+  public WxCpMaJsCode2SessionResult jsCode2Session(String jsCode) throws WxErrorException {
+    Map params = new HashMap<>(2);
+    params.put("js_code", jsCode);
+    params.put("grant_type", "authorization_code");
+
+    String result = this.get(configStorage.getApiUrl(JSCODE_TO_SESSION_URL), Joiner.on("&").withKeyValueSeparator("=").join(params));
+    return WxCpMaJsCode2SessionResult.fromJson(result);
+  }
+
+
+  @Override
+  public WxAccessToken getCorpToken(String authCorpid, String permanentCode) throws WxErrorException {
+	JsonObject jsonObject = new JsonObject();
+	jsonObject.addProperty("auth_corpid", authCorpid);
+	jsonObject.addProperty("permanent_code", permanentCode);
+	String result = post(configStorage.getApiUrl(GET_CORP_TOKEN), jsonObject.toString());
+	
+	return WxAccessToken.fromJson(result);
+  }
+  
+
+  @Override
+  public WxCpTpCorp getPermanentCode(String authCode) throws WxErrorException {
+    JsonObject jsonObject = new JsonObject();
+    jsonObject.addProperty("auth_code", authCode);
+
+    String result = post(configStorage.getApiUrl(GET_PERMANENT_CODE), jsonObject.toString());
+    jsonObject = new JsonParser().parse(result).getAsJsonObject();
+    WxCpTpCorp wxCpTpCorp = WxCpTpCorp.fromJson(jsonObject.get("auth_corp_info").getAsString());
+    wxCpTpCorp.setPermanentCode(jsonObject.get("permanent_code").getAsString());
+    return wxCpTpCorp;
+  }
+
+  @Override
+  public String get(String url, String queryParam) throws WxErrorException {
+    return execute(SimpleGetRequestExecutor.create(this), url, queryParam);
+  }
+
+  @Override
+  public String post(String url, String postData) throws WxErrorException {
+    return execute(SimplePostRequestExecutor.create(this), url, postData);
+  }
+
+  /**
+   * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求.
+   */
+  @Override
+  public  T execute(RequestExecutor executor, String uri, E data) throws WxErrorException {
+    int retryTimes = 0;
+    do {
+      try {
+        return this.executeInternal(executor, uri, data);
+      } catch (WxErrorException e) {
+        if (retryTimes + 1 > this.maxRetryTimes) {
+          this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
+          //最后一次重试失败后,直接抛出异常,不再等待
+          throw new RuntimeException("微信服务端异常,超出重试次数");
+        }
+
+        WxError error = e.getError();
+        /*
+         * -1 系统繁忙, 1000ms后重试
+         */
+        if (error.getErrorCode() == -1) {
+          int sleepMillis = this.retrySleepMillis * (1 << retryTimes);
+          try {
+            this.log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
+            Thread.sleep(sleepMillis);
+          } catch (InterruptedException e1) {
+            Thread.currentThread().interrupt();
+          }
+        } else {
+          throw e;
+        }
+      }
+    } while (retryTimes++ < this.maxRetryTimes);
+
+    this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
+    throw new RuntimeException("微信服务端异常,超出重试次数");
+  }
+
+  protected  T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException {
+    E dataForLog = DataUtils.handleDataWithSecret(data);
+
+    if (uri.contains("suite_access_token=")) {
+      throw new IllegalArgumentException("uri参数中不允许有suite_access_token: " + uri);
+    }
+    String suiteAccessToken = getSuiteAccessToken(false);
+
+    String uriWithAccessToken = uri + (uri.contains("?") ? "&" : "?") + "suite_access_token=" + suiteAccessToken;
+
+    try {
+      T result = executor.execute(uriWithAccessToken, data);
+      this.log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result);
+      return result;
+    } catch (WxErrorException e) {
+      WxError error = e.getError();
+      /*
+       * 发生以下情况时尝试刷新suite_access_token
+       * 42009 suite_access_token已过期
+       */
+      if (error.getErrorCode() == 42009) {
+        // 强制设置wxCpTpConfigStorage它的suite access token过期了,这样在下一次请求里就会刷新suite access token
+        this.configStorage.expireSuiteAccessToken();
+        return execute(executor, uri, data);
+      }
+
+      if (error.getErrorCode() != 0) {
+        this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error);
+        throw new WxErrorException(error, e);
+      }
+      return null;
+    } catch (IOException e) {
+      this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage());
+      throw new RuntimeException(e);
+    }
+  }
+
+  @Override
+  public void setWxCpTpConfigStorage(WxCpTpConfigStorage wxConfigProvider) {
+    this.configStorage = wxConfigProvider;
+    this.initHttp();
+  }
+
+  @Override
+  public void setRetrySleepMillis(int retrySleepMillis) {
+    this.retrySleepMillis = retrySleepMillis;
+  }
+
+
+  @Override
+  public void setMaxRetryTimes(int maxRetryTimes) {
+    this.maxRetryTimes = maxRetryTimes;
+  }
+
+  public File getTmpDirFile() {
+    return this.tmpDirFile;
+  }
+
+  public void setTmpDirFile(File tmpDirFile) {
+    this.tmpDirFile = tmpDirFile;
+  }
+
+  @Override
+  public RequestHttp getRequestHttp() {
+    return this;
+  }
+
+}
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 10c417729e..2dc5ca8755 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,11 +1,8 @@
 package me.chanjar.weixin.cp.api.impl;
 
-import java.util.List;
-
 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;
@@ -13,6 +10,8 @@
 import me.chanjar.weixin.cp.bean.WxCpAgent;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
+import java.util.List;
+
 
 /**
  * 
@@ -37,13 +36,14 @@ public WxCpAgent get(Integer agentId) throws WxErrorException {
       throw new IllegalArgumentException("缺少agentid参数");
     }
 
-    String responseContent = this.mainService.get(String.format(WxCpAgentService.GET_AGENT, agentId), null);
+    String responseContent = this.mainService.get(String.format(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpAgentService.GET_AGENT), agentId), null);
     return WxCpAgent.fromJson(responseContent);
   }
 
   @Override
   public void set(WxCpAgent agentInfo) throws WxErrorException {
-    String responseContent = this.mainService.post(WxCpAgentService.AGENT_SET, agentInfo.toJson());
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpAgentService.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));
@@ -52,7 +52,8 @@ public void set(WxCpAgent agentInfo) throws WxErrorException {
 
   @Override
   public List list() throws WxErrorException {
-    String responseContent = this.mainService.get(WxCpAgentService.AGENT_LIST, null);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpAgentService.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));
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java
index 0b1fb59381..1bf809502b 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java
@@ -47,7 +47,7 @@ public String chatCreate(String name, String owner, List users, String c
     if (StringUtils.isNotBlank(chatId)) {
       data.put("chatid", chatId);
     }
-    String result = this.cpService.post(APPCHAT_CREATE, WxGsonBuilder.create().toJson(data));
+    String result = this.cpService.post(this.cpService.getWxCpConfigStorage().getApiUrl(APPCHAT_CREATE), WxGsonBuilder.create().toJson(data));
     return new JsonParser().parse(result).getAsJsonObject().get("chatid").getAsString();
   }
 
@@ -76,7 +76,7 @@ public void chatUpdate(String chatId, String name, String owner, List us
       data.put("del_user_list", usersToDelete);
     }
 
-    this.cpService.post(APPCHAT_UPDATE, WxGsonBuilder.create().toJson(data));
+    this.cpService.post(this.cpService.getWxCpConfigStorage().getApiUrl(APPCHAT_UPDATE), WxGsonBuilder.create().toJson(data));
   }
 
   @Override
@@ -86,7 +86,7 @@ public void update(String chatId, String name, String owner, List usersT
 
   @Override
   public WxCpChat chatGet(String chatId) throws WxErrorException {
-    String result = this.cpService.get(APPCHAT_GET_CHATID + chatId, null);
+    String result = this.cpService.get(this.cpService.getWxCpConfigStorage().getApiUrl(APPCHAT_GET_CHATID + chatId), null);
     return WxCpGsonBuilder.create()
       .fromJson(JSON_PARSER.parse(result).getAsJsonObject().getAsJsonObject("chat_info").toString(), WxCpChat.class);
   }
@@ -98,7 +98,7 @@ public WxCpChat get(String chatId) throws WxErrorException {
 
   @Override
   public void sendMsg(WxCpAppChatMessage message) throws WxErrorException {
-    this.cpService.post(WxCpChatService.APPCHAT_SEND, message.toJson());
+    this.cpService.post(this.cpService.getWxCpConfigStorage().getApiUrl(WxCpChatService.APPCHAT_SEND), message.toJson());
   }
 
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java
index 09ded1b8b3..ce6f02ae5f 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java
@@ -1,7 +1,5 @@
 package me.chanjar.weixin.cp.api.impl;
 
-import java.util.List;
-
 import com.google.gson.JsonElement;
 import com.google.gson.JsonParser;
 import com.google.gson.reflect.TypeToken;
@@ -12,6 +10,8 @@
 import me.chanjar.weixin.cp.bean.WxCpDepart;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
+import java.util.List;
+
 /**
  * 
  *  部门管理接口
@@ -29,25 +29,27 @@ public WxCpDepartmentServiceImpl(WxCpService mainService) {
 
   @Override
   public Long create(WxCpDepart depart) throws WxErrorException {
-    String responseContent = this.mainService.post(WxCpDepartmentService.DEPARTMENT_CREATE, depart.toJson());
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpDepartmentService.DEPARTMENT_CREATE);
+    String responseContent = this.mainService.post(url, depart.toJson());
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return GsonHelper.getAsLong(tmpJsonElement.getAsJsonObject().get("id"));
   }
 
   @Override
   public void update(WxCpDepart group) throws WxErrorException {
-    this.mainService.post(WxCpDepartmentService.DEPARTMENT_UPDATE, group.toJson());
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpDepartmentService.DEPARTMENT_UPDATE);
+    this.mainService.post(url, group.toJson());
   }
 
   @Override
   public void delete(Long departId) throws WxErrorException {
-    String url = String.format(WxCpDepartmentService.DEPARTMENT_DELETE, departId);
+    String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpDepartmentService.DEPARTMENT_DELETE), departId);
     this.mainService.get(url, null);
   }
 
   @Override
   public List list(Long id) throws WxErrorException {
-    String url = WxCpDepartmentService.DEPARTMENT_LIST;
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpDepartmentService.DEPARTMENT_LIST);
     if (id != null) {
       url += "?id=" + id;
     }
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 7a3dc444cf..fa31a033ba 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,18 +1,19 @@
 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;
 import me.chanjar.weixin.common.util.http.BaseMediaDownloadRequestExecutor;
 import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
+import me.chanjar.weixin.cp.WxCpConsts;
 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;
+
 /**
  * 
  * 媒体管理接口.
@@ -37,7 +38,7 @@ public WxMediaUploadResult upload(String mediaType, String fileType, InputStream
   @Override
   public WxMediaUploadResult upload(String mediaType, File file) throws WxErrorException {
     return this.mainService.execute(MediaUploadRequestExecutor.create(this.mainService.getRequestHttp()),
-      MEDIA_UPLOAD_URL + mediaType, file);
+      this.mainService.getWxCpConfigStorage().getApiUrl(MEDIA_UPLOAD_URL + mediaType), file);
   }
 
   @Override
@@ -45,7 +46,7 @@ public File download(String mediaId) throws WxErrorException {
     return this.mainService.execute(
       BaseMediaDownloadRequestExecutor.create(this.mainService.getRequestHttp(),
         this.mainService.getWxCpConfigStorage().getTmpDirFile()),
-      MEDIA_GET_URL, "media_id=" + mediaId);
+      this.mainService.getWxCpConfigStorage().getApiUrl(MEDIA_GET_URL), "media_id=" + mediaId);
   }
 
   @Override
@@ -53,13 +54,13 @@ public File getJssdkFile(String mediaId) throws WxErrorException {
     return this.mainService.execute(
       BaseMediaDownloadRequestExecutor.create(this.mainService.getRequestHttp(),
         this.mainService.getWxCpConfigStorage().getTmpDirFile()),
-      JSSDK_MEDIA_GET_URL, "media_id=" + mediaId);
+      this.mainService.getWxCpConfigStorage().getApiUrl(JSSDK_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);
+      .execute(MediaUploadRequestExecutor.create(this.mainService.getRequestHttp()), this.mainService.getWxCpConfigStorage().getApiUrl(IMG_UPLOAD_URL), file);
     return result.getUrl();
   }
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java
index d33ade0191..a03d600145 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java
@@ -2,6 +2,7 @@
 
 import me.chanjar.weixin.common.bean.menu.WxMenu;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.cp.WxCpConsts;
 import me.chanjar.weixin.cp.api.WxCpMenuService;
 import me.chanjar.weixin.cp.api.WxCpService;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
@@ -28,7 +29,8 @@ public void create(WxMenu menu) throws WxErrorException {
 
   @Override
   public void create(Integer agentId, WxMenu menu) throws WxErrorException {
-    this.mainService.post(String.format(WxCpMenuService.MENU_CREATE, agentId), menu.toJson());
+    String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpMenuService.MENU_CREATE), agentId);
+    this.mainService.post(url, menu.toJson());
   }
 
   @Override
@@ -38,7 +40,7 @@ public void delete() throws WxErrorException {
 
   @Override
   public void delete(Integer agentId) throws WxErrorException {
-    String url = String.format(WxCpMenuService.MENU_DELETE, agentId);
+    String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpMenuService.MENU_DELETE), agentId);
     this.mainService.get(url, null);
   }
 
@@ -49,7 +51,7 @@ public WxMenu get() throws WxErrorException {
 
   @Override
   public WxMenu get(Integer agentId) throws WxErrorException {
-    String url = String.format(WxCpMenuService.MENU_GET, agentId);
+    String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpMenuService.MENU_GET), agentId);
     try {
       String resultContent = this.mainService.get(url, null);
       return WxCpGsonBuilder.create().fromJson(resultContent, WxMenu.class);
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 6ff91fc35a..aedc9ab24d 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
@@ -69,7 +69,7 @@ public WxCpOauth2UserInfo getUserInfo(String code) throws WxErrorException {
 
   @Override
   public WxCpOauth2UserInfo getUserInfo(Integer agentId, String code) throws WxErrorException {
-    String responseText = this.mainService.get(String.format(WxCpOAuth2Service.URL_GET_USER_INFO, code, agentId), null);
+    String responseText = this.mainService.get(String.format(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpOAuth2Service.URL_GET_USER_INFO), code, agentId), null);
     JsonElement je = new JsonParser().parse(responseText);
     JsonObject jo = je.getAsJsonObject();
 
@@ -86,7 +86,7 @@ public WxCpOauth2UserInfo getUserInfo(Integer agentId, String code) throws WxErr
   public WxCpUserDetail getUserDetail(String userTicket) throws WxErrorException {
     JsonObject param = new JsonObject();
     param.addProperty("user_ticket", userTicket);
-    String responseText = this.mainService.post(WxCpOAuth2Service.URL_GET_USER_DETAIL, param.toString());
+    String responseText = this.mainService.post(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpOAuth2Service.URL_GET_USER_DETAIL), param.toString());
     return WxCpGsonBuilder.create().fromJson(responseText, WxCpUserDetail.class);
   }
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java
index cc3b274495..c0f6ddaab6 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java
@@ -59,7 +59,7 @@ public List getCheckinData(Integer openCheckinDataType, Date st
 
     jsonObject.add("useridlist", jsonArray);
 
-    String responseContent = this.mainService.post(WxCpOaService.GET_CHECKIN_DATA, jsonObject.toString());
+    String responseContent = this.mainService.post(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpOaService.GET_CHECKIN_DATA), jsonObject.toString());
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return WxCpGsonBuilder.create()
       .fromJson(
@@ -88,7 +88,7 @@ public List getCheckinOption(Date datetime, List user
     jsonObject.addProperty("datetime", datetime.getTime() / 1000L);
     jsonObject.add("useridlist", jsonArray);
 
-    String responseContent = this.mainService.post(WxCpOaService.GET_CHECKIN_OPTION, jsonObject.toString());
+    String responseContent = this.mainService.post(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpOaService.GET_CHECKIN_OPTION), jsonObject.toString());
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
 
     return WxCpGsonBuilder.create()
@@ -108,7 +108,7 @@ public WxCpApprovalDataResult getApprovalData(Date startTime, Date endTime, Long
       jsonObject.addProperty("next_spnum", nextSpnum);
     }
 
-    String responseContent = this.mainService.post(WxCpOaService.GET_APPROVAL_DATA, jsonObject.toString());
+    String responseContent = this.mainService.post(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpOaService.GET_APPROVAL_DATA), jsonObject.toString());
     return WxCpGsonBuilder.create().fromJson(responseContent, WxCpApprovalDataResult.class);
   }
 
@@ -140,7 +140,7 @@ public List getDialRecord(Date startTime, Date endTime, Integer
       jsonObject.addProperty("end_time", endtimestamp);
     }
 
-    String responseContent = this.mainService.post(WxCpOaService.GET_DIAL_RECORD, jsonObject.toString());
+    String responseContent = this.mainService.post(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpOaService.GET_DIAL_RECORD), jsonObject.toString());
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
 
     return WxCpGsonBuilder.create()
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java
index 11a183b507..6dea258b99 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java
@@ -48,7 +48,8 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
     }
 
     synchronized (this.globalAccessTokenRefreshLock) {
-      String url = String.format(WxCpService.GET_TOKEN, this.configStorage.getCorpId(), this.configStorage.getCorpSecret());
+      String url = String.format(this.configStorage.getApiUrl(WxCpService.GET_TOKEN), this.configStorage.getCorpId(), this.configStorage.getCorpSecret());
+
       try {
         HttpGet httpGet = new HttpGet(url);
         if (this.httpProxy != null) {
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java
index d5d08900b9..f1c5c8419a 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java
@@ -1,6 +1,10 @@
 package me.chanjar.weixin.cp.api.impl;
 
-import jodd.http.*;
+import jodd.http.HttpConnectionProvider;
+import jodd.http.HttpRequest;
+import jodd.http.HttpResponse;
+import jodd.http.JoddHttp;
+import jodd.http.ProxyInfo;
 import me.chanjar.weixin.common.WxType;
 import me.chanjar.weixin.common.bean.WxAccessToken;
 import me.chanjar.weixin.common.error.WxError;
@@ -39,7 +43,7 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
     }
 
     synchronized (this.globalAccessTokenRefreshLock) {
-      HttpRequest request = HttpRequest.get(String.format(WxCpService.GET_TOKEN, this.configStorage.getCorpId(), this.configStorage.getCorpSecret()));
+      HttpRequest request = HttpRequest.get(String.format(this.configStorage.getApiUrl(WxCpService.GET_TOKEN), this.configStorage.getCorpId(), this.configStorage.getCorpSecret()));
       if (this.httpProxy != null) {
         httpClient.useProxy(this.httpProxy);
       }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java
index f4cc540f3c..4280174dc4 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java
@@ -8,7 +8,12 @@
 import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
 import me.chanjar.weixin.cp.api.WxCpService;
 import me.chanjar.weixin.cp.config.WxCpConfigStorage;
-import okhttp3.*;
+import okhttp3.Authenticator;
+import okhttp3.Credentials;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import okhttp3.Route;
 
 import java.io.IOException;
 
@@ -45,7 +50,7 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
       OkHttpClient client = getRequestHttpClient();
       //请求的request
       Request request = new Request.Builder()
-        .url(String.format(WxCpService.GET_TOKEN, this.configStorage.getCorpId(), this.configStorage.getCorpSecret()))
+        .url(String.format(this.configStorage.getApiUrl(WxCpService.GET_TOKEN), this.configStorage.getCorpId(), this.configStorage.getCorpSecret()))
         .get()
         .build();
       String resultContent = null;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java
index 413436207f..ee0db6da9f 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java
@@ -1,6 +1,10 @@
 package me.chanjar.weixin.cp.api.impl;
 
-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;
@@ -32,27 +36,31 @@ public WxCpTagServiceImpl(WxCpService mainService) {
   public String create(String tagName) throws WxErrorException {
     JsonObject o = new JsonObject();
     o.addProperty("tagname", tagName);
-    String responseContent = this.mainService.post(WxCpTagService.TAG_CREATE, o.toString());
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpTagService.TAG_CREATE);
+    String responseContent = this.mainService.post(url, o.toString());
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return tmpJsonElement.getAsJsonObject().get("tagid").getAsString();
   }
 
   @Override
   public void update(String tagId, String tagName) throws WxErrorException {
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpTagService.TAG_UPDATE);
     JsonObject o = new JsonObject();
     o.addProperty("tagid", tagId);
     o.addProperty("tagname", tagName);
-    this.mainService.post(WxCpTagService.TAG_UPDATE, o.toString());
+    this.mainService.post(url, o.toString());
   }
 
   @Override
   public void delete(String tagId) throws WxErrorException {
-    this.mainService.get(String.format(WxCpTagService.TAG_DELETE, tagId), null);
+    String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpTagService.TAG_DELETE), tagId);
+    this.mainService.get(url, null);
   }
 
   @Override
   public List listAll() throws WxErrorException {
-    String responseContent = this.mainService.get(WxCpTagService.TAG_LIST, null);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpTagService.TAG_LIST);
+    String responseContent = this.mainService.get(url, null);
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return WxCpGsonBuilder.create()
       .fromJson(
@@ -64,7 +72,8 @@ public List listAll() throws WxErrorException {
 
   @Override
   public List listUsersByTagId(String tagId) throws WxErrorException {
-    String responseContent = this.mainService.get(String.format(WxCpTagService.TAG_GET, tagId), null);
+    String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpTagService.TAG_GET), tagId);
+    String responseContent = this.mainService.get(url, null);
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return WxCpGsonBuilder.create()
       .fromJson(
@@ -76,20 +85,22 @@ public List listUsersByTagId(String tagId) throws WxErrorException {
 
   @Override
   public WxCpTagAddOrRemoveUsersResult addUsers2Tag(String tagId, List userIds, List partyIds) throws WxErrorException {
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpTagService.TAG_ADDTAGUSERS);
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("tagid", tagId);
     this.addUserIdsAndPartyIdsToJson(userIds, partyIds, jsonObject);
 
-    return WxCpTagAddOrRemoveUsersResult.fromJson(this.mainService.post(WxCpTagService.TAG_ADDTAGUSERS, jsonObject.toString()));
+    return WxCpTagAddOrRemoveUsersResult.fromJson(this.mainService.post(url, jsonObject.toString()));
   }
 
   @Override
   public WxCpTagAddOrRemoveUsersResult removeUsersFromTag(String tagId, List userIds, List partyIds) throws WxErrorException {
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpTagService.TAG_DELTAGUSERS);
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("tagid", tagId);
     this.addUserIdsAndPartyIdsToJson(userIds, partyIds, jsonObject);
 
-    return WxCpTagAddOrRemoveUsersResult.fromJson(this.mainService.post(WxCpTagService.TAG_DELTAGUSERS, jsonObject.toString()));
+    return WxCpTagAddOrRemoveUsersResult.fromJson(this.mainService.post(url, jsonObject.toString()));
   }
 
   private void addUserIdsAndPartyIdsToJson(List userIds, List partyIds, JsonObject jsonObject) {
@@ -116,7 +127,8 @@ public WxCpTagGetResult get(String tagId) throws WxErrorException {
       throw new IllegalArgumentException("缺少tagId参数");
     }
 
-    String responseContent = this.mainService.get(String.format(WxCpTagService.TAG_GET, tagId), null);
+    String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpTagService.TAG_GET), tagId);
+    String responseContent = this.mainService.get(url, null);
     return WxCpTagGetResult.fromJson(responseContent);
   }
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTaskCardServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTaskCardServiceImpl.java
index e70a7d376a..a2efabb497 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTaskCardServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTaskCardServiceImpl.java
@@ -3,6 +3,7 @@
 import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.json.WxGsonBuilder;
+import me.chanjar.weixin.cp.WxCpConsts;
 import me.chanjar.weixin.cp.api.WxCpService;
 import me.chanjar.weixin.cp.api.WxCpTaskCardService;
 
@@ -33,6 +34,7 @@ public void update(List userIds, String taskId, String clickedKey) throw
     data.put("task_id", taskId);
     data.put("clicked_key", clickedKey);
 
-    this.mainService.post(MESSAGE_UPDATE_TASKCARD, WxGsonBuilder.create().toJson(data));
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(MESSAGE_UPDATE_TASKCARD);
+    this.mainService.post(url, WxGsonBuilder.create().toJson(data));
   }
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceApacheHttpClientImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceApacheHttpClientImpl.java
index f673a622bd..04bc0a5f6e 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceApacheHttpClientImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceApacheHttpClientImpl.java
@@ -52,7 +52,7 @@ public String getSuiteAccessToken(boolean forceRefresh) throws WxErrorException
 
     synchronized (this.globalSuiteAccessTokenRefreshLock) {
       try {
-        HttpPost httpPost = new HttpPost(WxCpTpService.GET_SUITE_TOKEN);
+        HttpPost httpPost = new HttpPost(configStorage.getApiUrl(WxCpTpService.GET_SUITE_TOKEN));
         if (this.httpProxy != null) {
           RequestConfig config = RequestConfig.custom()
             .setProxy(this.httpProxy).build();
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 b3b0909522..c38a680125 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,8 +1,5 @@
 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.JsonArray;
 import com.google.gson.JsonElement;
@@ -11,6 +8,7 @@
 import com.google.gson.JsonPrimitive;
 import com.google.gson.reflect.TypeToken;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.cp.WxCpConsts;
 import me.chanjar.weixin.cp.api.WxCpService;
 import me.chanjar.weixin.cp.api.WxCpUserService;
 import me.chanjar.weixin.cp.bean.WxCpInviteResult;
@@ -18,6 +16,9 @@
 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.
@@ -34,23 +35,26 @@ public WxCpUserServiceImpl(WxCpService mainService) {
 
   @Override
   public void authenticate(String userId) throws WxErrorException {
-    this.mainService.get(WxCpUserService.URL_AUTHENTICATE + userId, null);
+    this.mainService.get(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpUserService.URL_AUTHENTICATE + userId), null);
   }
 
   @Override
   public void create(WxCpUser user) throws WxErrorException {
-    this.mainService.post(WxCpUserService.URL_USER_CREATE, user.toJson());
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpUserService.URL_USER_CREATE);
+    this.mainService.post(url, user.toJson());
   }
 
   @Override
   public void update(WxCpUser user) throws WxErrorException {
-    this.mainService.post(WxCpUserService.URL_USER_UPDATE, user.toJson());
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpUserService.URL_USER_UPDATE);
+    this.mainService.post(url, user.toJson());
   }
 
   @Override
   public void delete(String... userIds) throws WxErrorException {
     if (userIds.length == 1) {
-      this.mainService.get(WxCpUserService.URL_USER_DELETE + userIds[0], null);
+      String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpUserService.URL_USER_DELETE + userIds[0]);
+      this.mainService.get(url, null);
       return;
     }
 
@@ -66,7 +70,8 @@ public void delete(String... userIds) throws WxErrorException {
 
   @Override
   public WxCpUser getById(String userid) throws WxErrorException {
-    String responseContent = this.mainService.get(WxCpUserService.URL_USER_GET + userid, null);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpUserService.URL_USER_GET + userid);
+    String responseContent = this.mainService.get(url, null);
     return WxCpUser.fromJson(responseContent);
   }
 
@@ -82,7 +87,8 @@ public List listByDepartment(Long departId, Boolean fetchChild, Intege
       params += "&status=0";
     }
 
-    String responseContent = this.mainService.get(WxCpUserService.URL_USER_LIST + departId, params);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpUserService.URL_USER_LIST + departId);
+    String responseContent = this.mainService.get(url, params);
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return WxCpGsonBuilder.create()
       .fromJson(tmpJsonElement.getAsJsonObject().get("userlist"),
@@ -103,7 +109,8 @@ public List listSimpleByDepartment(Long departId, Boolean fetchChild,
       params += "&status=0";
     }
 
-    String responseContent = this.mainService.get(WxCpUserService.URL_USER_SIMPLE_LIST + departId, params);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpUserService.URL_USER_SIMPLE_LIST + departId);
+    String responseContent = this.mainService.get(url, params);
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return WxCpGsonBuilder.create()
       .fromJson(
@@ -140,18 +147,20 @@ public WxCpInviteResult invite(List userIds, List partyIds, List
       jsonObject.add("tag", jsonArray);
     }
 
-    return WxCpInviteResult.fromJson(this.mainService.post(WxCpUserService.URL_BATCH_INVITE, jsonObject.toString()));
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpUserService.URL_BATCH_INVITE);
+    return WxCpInviteResult.fromJson(this.mainService.post(url, jsonObject.toString()));
   }
 
   @Override
   public Map userId2Openid(String userId, Integer agentId) throws WxErrorException {
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpUserService.URL_CONVERT_TO_OPENID);
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("userid", userId);
     if (agentId != null) {
       jsonObject.addProperty("agentid", agentId);
     }
 
-    String responseContent = this.mainService.post(WxCpUserService.URL_CONVERT_TO_OPENID, jsonObject.toString());
+    String responseContent = this.mainService.post(url, jsonObject.toString());
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     Map result = Maps.newHashMap();
     if (tmpJsonElement.getAsJsonObject().get("openid") != null) {
@@ -169,14 +178,16 @@ public Map userId2Openid(String userId, Integer agentId) throws
   public String openid2UserId(String openid) throws WxErrorException {
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("openid", openid);
-    String responseContent = this.mainService.post(WxCpUserService.URL_CONVERT_TO_USERID, jsonObject.toString());
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpUserService.URL_CONVERT_TO_USERID);
+    String responseContent = this.mainService.post(url, jsonObject.toString());
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return tmpJsonElement.getAsJsonObject().get("userid").getAsString();
   }
 
   @Override
   public WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException {
-    String responseContent = this.mainService.get(WxCpUserService.URL_GET_EXTERNAL_CONTACT + userId, null);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpUserService.URL_GET_EXTERNAL_CONTACT + 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/config/WxCpConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java
index e13738142f..a75ad1dfb1 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java
@@ -12,6 +12,22 @@
  */
 public interface WxCpConfigStorage {
 
+  /**
+   * 设置企业微信服务器 baseUrl.
+   *
+   * 默认值是 https://qyapi.weixin.qq.com , 如果使用默认值,则不需要调用 setBaseApiUrl
+   *
+   * @param baseUrl 企业微信服务器 Url
+   */
+  void setBaseApiUrl(String baseUrl);
+
+  /**
+   * 读取企业微信 API Url.
+   *
+   * 支持私有化企业微信服务器.
+   */
+  String getApiUrl(String path);
+
   String getAccessToken();
 
   boolean isAccessTokenExpired();
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 a501edeb6e..31e2a211d5 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
@@ -39,6 +39,21 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage {
 
   private volatile ApacheHttpClientBuilder apacheHttpClientBuilder;
 
+  protected volatile String baseApiUrl;
+
+  @Override
+  public void setBaseApiUrl(String baseUrl) {
+    this.baseApiUrl = baseUrl;
+  }
+
+  @Override
+  public String getApiUrl(String path) {
+    if (baseApiUrl == null) {
+      baseApiUrl = "https://qyapi.weixin.qq.com";
+    }
+    return baseApiUrl + path;
+  }
+
   @Override
   public String getAccessToken() {
     return this.accessToken;
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 7c72de0e1b..b8deef1d51 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
@@ -38,6 +38,21 @@ public class WxCpJedisConfigStorage implements WxCpConfigStorage {
   private volatile File tmpDirFile;
   private volatile ApacheHttpClientBuilder apacheHttpClientBuilder;
 
+  protected volatile String baseApiUrl;
+
+  @Override
+  public void setBaseApiUrl(String baseUrl) {
+    this.baseApiUrl = baseUrl;
+  }
+
+  @Override
+  public String getApiUrl(String path) {
+    if (baseApiUrl == null) {
+      baseApiUrl = "https://qyapi.weixin.qq.com";
+    }
+    return baseApiUrl + path;
+  }
+
   public WxCpJedisConfigStorage(JedisPool jedisPool) {
     this.jedisPool = jedisPool;
   }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java
index a132dd1024..44ef4e17be 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java
@@ -1,72 +1,88 @@
-package me.chanjar.weixin.cp.config;
-
-import me.chanjar.weixin.common.bean.WxAccessToken;
-import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
-
-import java.io.File;
-
-/**
- * 微信客户端(第三方应用)配置存储
- *
- * @author zhenjun cai
- */
-public interface WxCpTpConfigStorage {
-
-  String getSuiteAccessToken();
-
-  boolean isSuiteAccessTokenExpired();
-
-  /**
-   * 强制将suite access token过期掉
-   */
-  void expireSuiteAccessToken();
-
-  void updateSuiteAccessToken(WxAccessToken suiteAccessToken);
-
-  void updateSuiteAccessToken(String suiteAccessToken, int expiresIn);
-
-  String getSuiteTicket();
-
-  boolean isSuiteTicketExpired();
-
-  /**
-   * 强制将suite ticket过期掉
-   */
-  void expireSuiteTicket();
-
-  /**
-   * 应该是线程安全的
-   */
-  void updateSuiteTicket(String suiteTicket, int expiresInSeconds);
-  
-  String getCorpId();
-
-  String getCorpSecret();
-
-  String getSuiteId();
-
-  String getSuiteSecret();
-
-  String getToken();
-
-  String getAesKey();
-
-  long getExpiresTime();
-
-  String getHttpProxyHost();
-
-  int getHttpProxyPort();
-
-  String getHttpProxyUsername();
-
-  String getHttpProxyPassword();
-
-  File getTmpDirFile();
-
-  /**
-   * http client builder
-   *
-   * @return ApacheHttpClientBuilder
-   */
-  ApacheHttpClientBuilder getApacheHttpClientBuilder();
-}
+package me.chanjar.weixin.cp.config;
+
+import me.chanjar.weixin.common.bean.WxAccessToken;
+import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
+
+import java.io.File;
+
+/**
+ * 微信客户端(第三方应用)配置存储
+ *
+ * @author zhenjun cai
+ */
+public interface WxCpTpConfigStorage {
+
+  /**
+   * 设置企业微信服务器 baseUrl.
+   *
+   * 默认值是 https://qyapi.weixin.qq.com , 如果使用默认值,则不需要调用 setBaseApiUrl
+   *
+   * @param baseUrl 企业微信服务器 Url
+   */
+  void setBaseApiUrl(String baseUrl);
+
+  /**
+   * 读取企业微信 API Url.
+   *
+   * 支持私有化企业微信服务器.
+   */
+  String getApiUrl(String path);
+
+  String getSuiteAccessToken();
+
+  boolean isSuiteAccessTokenExpired();
+
+  /**
+   * 强制将suite access token过期掉
+   */
+  void expireSuiteAccessToken();
+
+  void updateSuiteAccessToken(WxAccessToken suiteAccessToken);
+
+  void updateSuiteAccessToken(String suiteAccessToken, int expiresIn);
+
+  String getSuiteTicket();
+
+  boolean isSuiteTicketExpired();
+
+  /**
+   * 强制将suite ticket过期掉
+   */
+  void expireSuiteTicket();
+
+  /**
+   * 应该是线程安全的
+   */
+  void updateSuiteTicket(String suiteTicket, int expiresInSeconds);
+  
+  String getCorpId();
+
+  String getCorpSecret();
+
+  String getSuiteId();
+
+  String getSuiteSecret();
+
+  String getToken();
+
+  String getAesKey();
+
+  long getExpiresTime();
+
+  String getHttpProxyHost();
+
+  int getHttpProxyPort();
+
+  String getHttpProxyUsername();
+
+  String getHttpProxyPassword();
+
+  File getTmpDirFile();
+
+  /**
+   * http client builder
+   *
+   * @return ApacheHttpClientBuilder
+   */
+  ApacheHttpClientBuilder getApacheHttpClientBuilder();
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpInMemoryConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpInMemoryConfigStorage.java
index c135c95b7f..6da47f5b72 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpInMemoryConfigStorage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpInMemoryConfigStorage.java
@@ -1,230 +1,245 @@
-package me.chanjar.weixin.cp.config;
-
-import me.chanjar.weixin.common.bean.WxAccessToken;
-import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
-import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
-
-import java.io.File;
-
-/**
- * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化
- *
- * @author Daniel Qian
- */
-public class WxCpTpInMemoryConfigStorage implements WxCpTpConfigStorage {
-  protected volatile String corpId;
-  protected volatile String corpSecret;
-  
-  protected volatile String suiteId;
-  protected volatile String suiteSecret;
-
-  protected volatile String token;
-  protected volatile String suiteAccessToken;
-  protected volatile String aesKey;
-  protected volatile long expiresTime;
-
-  protected volatile String oauth2redirectUri;
-
-  protected volatile String httpProxyHost;
-  protected volatile int httpProxyPort;
-  protected volatile String httpProxyUsername;
-  protected volatile String httpProxyPassword;
-
-  protected volatile String suiteTicket;
-  protected volatile long suiteTicketExpiresTime;
-
-
-  protected volatile File tmpDirFile;
-
-  private volatile ApacheHttpClientBuilder apacheHttpClientBuilder;
-
-  @Override
-  public String getSuiteAccessToken() {
-    return this.suiteAccessToken;
-  }
-  
-  public void setSuiteAccessToken(String suiteAccessToken) {
-    this.suiteAccessToken = suiteAccessToken;
-  }
-
-  @Override
-  public boolean isSuiteAccessTokenExpired() {
-    return System.currentTimeMillis() > this.expiresTime;
-  }
-
-  @Override
-  public void expireSuiteAccessToken() {
-    this.expiresTime = 0;
-  }
-
-  @Override
-  public synchronized void updateSuiteAccessToken(WxAccessToken suiteAccessToken) {
-	  updateSuiteAccessToken(suiteAccessToken.getAccessToken(), suiteAccessToken.getExpiresIn());
-  }
-
-  @Override
-  public synchronized void updateSuiteAccessToken(String suiteAccessToken, int expiresInSeconds) {
-    this.suiteAccessToken = suiteAccessToken;
-    this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
-  }
-  
-  @Override
-  public String getCorpId() {
-    return this.corpId;
-  }
-  
-  public void setCorpId(String corpId) {
-    this.corpId = corpId;
-  }
-  
-  @Override
-  public String getCorpSecret() {
-    return this.corpSecret;
-  }
-  
-  public void setCorpSecret(String corpSecret) {
-    this.corpSecret = corpSecret;
-  }
-  
-  @Override
-  public String getSuiteTicket() {
-    return this.suiteTicket;
-  }
-
-  public void setSuiteTicket(String suiteTicket) {
-    this.suiteTicket = suiteTicket;
-  }
-
-  public long getSuiteTicketExpiresTime() {
-    return this.suiteTicketExpiresTime;
-  }
-
-  public void setSuiteTicketExpiresTime(long suiteTicketExpiresTime) {
-    this.suiteTicketExpiresTime = suiteTicketExpiresTime;
-  }
-
-  @Override
-  public boolean isSuiteTicketExpired() {
-    return System.currentTimeMillis() > this.suiteTicketExpiresTime;
-  }
-
-  @Override
-  public synchronized void updateSuiteTicket(String suiteTicket, int expiresInSeconds) {
-    this.suiteTicket = suiteTicket;
-    // 预留200秒的时间
-    this.suiteTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
-  }
-
-  @Override
-  public void expireSuiteTicket() {
-    this.suiteTicketExpiresTime = 0;
-  }
-
-  @Override
-  public String getSuiteId() {
-    return this.suiteId;
-  }
-
-  public void setSuiteId(String corpId) {
-    this.suiteId = corpId;
-  }
-
-  @Override
-  public String getSuiteSecret() {
-    return this.suiteSecret;
-  }
-
-  public void setSuiteSecret(String corpSecret) {
-    this.suiteSecret = corpSecret;
-  }
-
-  @Override
-  public String getToken() {
-    return this.token;
-  }
-
-  public void setToken(String token) {
-    this.token = token;
-  }
-
-  @Override
-  public long getExpiresTime() {
-    return this.expiresTime;
-  }
-
-  public void setExpiresTime(long expiresTime) {
-    this.expiresTime = expiresTime;
-  }
-
-  @Override
-  public String getAesKey() {
-    return this.aesKey;
-  }
-
-  public void setAesKey(String aesKey) {
-    this.aesKey = aesKey;
-  }
-
-  public void setOauth2redirectUri(String oauth2redirectUri) {
-    this.oauth2redirectUri = oauth2redirectUri;
-  }
-
-  @Override
-  public String getHttpProxyHost() {
-    return this.httpProxyHost;
-  }
-
-  public void setHttpProxyHost(String httpProxyHost) {
-    this.httpProxyHost = httpProxyHost;
-  }
-
-  @Override
-  public int getHttpProxyPort() {
-    return this.httpProxyPort;
-  }
-
-  public void setHttpProxyPort(int httpProxyPort) {
-    this.httpProxyPort = httpProxyPort;
-  }
-
-  @Override
-  public String getHttpProxyUsername() {
-    return this.httpProxyUsername;
-  }
-
-  public void setHttpProxyUsername(String httpProxyUsername) {
-    this.httpProxyUsername = httpProxyUsername;
-  }
-
-  @Override
-  public String getHttpProxyPassword() {
-    return this.httpProxyPassword;
-  }
-
-  public void setHttpProxyPassword(String httpProxyPassword) {
-    this.httpProxyPassword = httpProxyPassword;
-  }
-
-  @Override
-  public String toString() {
-    return WxCpGsonBuilder.create().toJson(this);
-  }
-
-  @Override
-  public File getTmpDirFile() {
-    return this.tmpDirFile;
-  }
-
-  public void setTmpDirFile(File tmpDirFile) {
-    this.tmpDirFile = tmpDirFile;
-  }
-
-  @Override
-  public ApacheHttpClientBuilder getApacheHttpClientBuilder() {
-    return this.apacheHttpClientBuilder;
-  }
-
-  public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) {
-    this.apacheHttpClientBuilder = apacheHttpClientBuilder;
-  }
-}
+package me.chanjar.weixin.cp.config;
+
+import me.chanjar.weixin.common.bean.WxAccessToken;
+import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+import java.io.File;
+
+/**
+ * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化
+ *
+ * @author Daniel Qian
+ */
+public class WxCpTpInMemoryConfigStorage implements WxCpTpConfigStorage {
+  protected volatile String corpId;
+  protected volatile String corpSecret;
+  
+  protected volatile String suiteId;
+  protected volatile String suiteSecret;
+
+  protected volatile String token;
+  protected volatile String suiteAccessToken;
+  protected volatile String aesKey;
+  protected volatile long expiresTime;
+
+  protected volatile String oauth2redirectUri;
+
+  protected volatile String httpProxyHost;
+  protected volatile int httpProxyPort;
+  protected volatile String httpProxyUsername;
+  protected volatile String httpProxyPassword;
+
+  protected volatile String suiteTicket;
+  protected volatile long suiteTicketExpiresTime;
+
+
+  protected volatile File tmpDirFile;
+
+  private volatile ApacheHttpClientBuilder apacheHttpClientBuilder;
+
+  protected volatile String baseApiUrl;
+
+  @Override
+  public void setBaseApiUrl(String baseUrl) {
+    this.baseApiUrl = baseUrl;
+  }
+
+  @Override
+  public String getApiUrl(String path) {
+    if (baseApiUrl == null) {
+      baseApiUrl = "https://qyapi.weixin.qq.com";
+    }
+    return baseApiUrl + path;
+  }
+
+  @Override
+  public String getSuiteAccessToken() {
+    return this.suiteAccessToken;
+  }
+  
+  public void setSuiteAccessToken(String suiteAccessToken) {
+    this.suiteAccessToken = suiteAccessToken;
+  }
+
+  @Override
+  public boolean isSuiteAccessTokenExpired() {
+    return System.currentTimeMillis() > this.expiresTime;
+  }
+
+  @Override
+  public void expireSuiteAccessToken() {
+    this.expiresTime = 0;
+  }
+
+  @Override
+  public synchronized void updateSuiteAccessToken(WxAccessToken suiteAccessToken) {
+	  updateSuiteAccessToken(suiteAccessToken.getAccessToken(), suiteAccessToken.getExpiresIn());
+  }
+
+  @Override
+  public synchronized void updateSuiteAccessToken(String suiteAccessToken, int expiresInSeconds) {
+    this.suiteAccessToken = suiteAccessToken;
+    this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
+  }
+  
+  @Override
+  public String getCorpId() {
+    return this.corpId;
+  }
+  
+  public void setCorpId(String corpId) {
+    this.corpId = corpId;
+  }
+  
+  @Override
+  public String getCorpSecret() {
+    return this.corpSecret;
+  }
+  
+  public void setCorpSecret(String corpSecret) {
+    this.corpSecret = corpSecret;
+  }
+  
+  @Override
+  public String getSuiteTicket() {
+    return this.suiteTicket;
+  }
+
+  public void setSuiteTicket(String suiteTicket) {
+    this.suiteTicket = suiteTicket;
+  }
+
+  public long getSuiteTicketExpiresTime() {
+    return this.suiteTicketExpiresTime;
+  }
+
+  public void setSuiteTicketExpiresTime(long suiteTicketExpiresTime) {
+    this.suiteTicketExpiresTime = suiteTicketExpiresTime;
+  }
+
+  @Override
+  public boolean isSuiteTicketExpired() {
+    return System.currentTimeMillis() > this.suiteTicketExpiresTime;
+  }
+
+  @Override
+  public synchronized void updateSuiteTicket(String suiteTicket, int expiresInSeconds) {
+    this.suiteTicket = suiteTicket;
+    // 预留200秒的时间
+    this.suiteTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
+  }
+
+  @Override
+  public void expireSuiteTicket() {
+    this.suiteTicketExpiresTime = 0;
+  }
+
+  @Override
+  public String getSuiteId() {
+    return this.suiteId;
+  }
+
+  public void setSuiteId(String corpId) {
+    this.suiteId = corpId;
+  }
+
+  @Override
+  public String getSuiteSecret() {
+    return this.suiteSecret;
+  }
+
+  public void setSuiteSecret(String corpSecret) {
+    this.suiteSecret = corpSecret;
+  }
+
+  @Override
+  public String getToken() {
+    return this.token;
+  }
+
+  public void setToken(String token) {
+    this.token = token;
+  }
+
+  @Override
+  public long getExpiresTime() {
+    return this.expiresTime;
+  }
+
+  public void setExpiresTime(long expiresTime) {
+    this.expiresTime = expiresTime;
+  }
+
+  @Override
+  public String getAesKey() {
+    return this.aesKey;
+  }
+
+  public void setAesKey(String aesKey) {
+    this.aesKey = aesKey;
+  }
+
+  public void setOauth2redirectUri(String oauth2redirectUri) {
+    this.oauth2redirectUri = oauth2redirectUri;
+  }
+
+  @Override
+  public String getHttpProxyHost() {
+    return this.httpProxyHost;
+  }
+
+  public void setHttpProxyHost(String httpProxyHost) {
+    this.httpProxyHost = httpProxyHost;
+  }
+
+  @Override
+  public int getHttpProxyPort() {
+    return this.httpProxyPort;
+  }
+
+  public void setHttpProxyPort(int httpProxyPort) {
+    this.httpProxyPort = httpProxyPort;
+  }
+
+  @Override
+  public String getHttpProxyUsername() {
+    return this.httpProxyUsername;
+  }
+
+  public void setHttpProxyUsername(String httpProxyUsername) {
+    this.httpProxyUsername = httpProxyUsername;
+  }
+
+  @Override
+  public String getHttpProxyPassword() {
+    return this.httpProxyPassword;
+  }
+
+  public void setHttpProxyPassword(String httpProxyPassword) {
+    this.httpProxyPassword = httpProxyPassword;
+  }
+
+  @Override
+  public String toString() {
+    return WxCpGsonBuilder.create().toJson(this);
+  }
+
+  @Override
+  public File getTmpDirFile() {
+    return this.tmpDirFile;
+  }
+
+  public void setTmpDirFile(File tmpDirFile) {
+    this.tmpDirFile = tmpDirFile;
+  }
+
+  @Override
+  public ApacheHttpClientBuilder getApacheHttpClientBuilder() {
+    return this.apacheHttpClientBuilder;
+  }
+
+  public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) {
+    this.apacheHttpClientBuilder = apacheHttpClientBuilder;
+  }
+}
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 a2dc46e826..9fabe55068 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
@@ -2,6 +2,7 @@
 
 import com.google.inject.Inject;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.cp.WxCpConsts;
 import me.chanjar.weixin.cp.api.ApiTestModule;
 import me.chanjar.weixin.cp.api.WxCpAgentService;
 import me.chanjar.weixin.cp.api.WxCpService;
@@ -14,7 +15,6 @@
 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;
 
 
 /**
@@ -70,7 +70,7 @@ public static class MockTest {
     @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(String.format(WxCpAgentService.GET_AGENT, 9), null)).thenReturn(returnJson);
+      when(wxService.get(String.format(wxService.getWxCpConfigStorage().getApiUrl(WxCpAgentService.GET_AGENT), 9), null)).thenReturn(returnJson);
       when(wxService.getAgentService()).thenReturn(new WxCpAgentServiceImpl(wxService));
 
       WxCpAgentService wxAgentService = this.wxService.getAgentService();
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java
index c4c8b3ccb5..858fde203c 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java
@@ -17,7 +17,6 @@
 
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotEquals;
 
 /**
@@ -83,7 +82,7 @@ public void testDelete() throws Exception {
   public void testGet() throws WxErrorException {
     String apiResultJson = "{\"errcode\": 0,\"errmsg\": \"ok\",\"userlist\": [{\"userid\": \"0124035\",\"name\": \"王五\"},{\"userid\": \"0114035\",\"name\": \"梦雪\"}],\"partylist\": [9576,9567,9566],\"tagname\": \"测试标签-001\"}";
     WxCpService wxService = mock(WxCpService.class);
-    when(wxService.get(String.format(WxCpTagService.TAG_GET, 150), null)).thenReturn(apiResultJson);
+    when(wxService.get(String.format(wxService.getWxCpConfigStorage().getApiUrl(WxCpTagService.TAG_GET), 150), null)).thenReturn(apiResultJson);
     when(wxService.getTagService()).thenReturn(new WxCpTagServiceImpl(wxService));
 
     WxCpTagService wxCpTagService = wxService.getTagService();

From 07d0656deca2a11364e2cf3c73aa2092c7210290 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sun, 2 Jun 2019 15:23:11 +0800
Subject: [PATCH 11/74] =?UTF-8?q?=E4=BC=81=E4=B8=9A=E5=BE=AE=E4=BF=A1?=
 =?UTF-8?q?=E6=A8=A1=E5=9D=97=E6=8E=A5=E5=8F=A3=E5=9C=B0=E5=9D=80=E5=B8=B8?=
 =?UTF-8?q?=E9=87=8F=E4=BC=98=E5=8C=96=E9=87=8D=E6=9E=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../weixin/cp/api/WxCpAgentService.java       |   4 -
 .../weixin/cp/api/WxCpChatService.java        |   4 -
 .../weixin/cp/api/WxCpDepartmentService.java  |   4 -
 .../weixin/cp/api/WxCpMediaService.java       |   4 -
 .../weixin/cp/api/WxCpMenuService.java        |   3 -
 .../weixin/cp/api/WxCpOAuth2Service.java      |   3 -
 .../chanjar/weixin/cp/api/WxCpOaService.java  |   4 -
 .../me/chanjar/weixin/cp/api/WxCpService.java |  10 --
 .../chanjar/weixin/cp/api/WxCpTagService.java |   7 --
 .../weixin/cp/api/WxCpTaskCardService.java    |   1 -
 .../chanjar/weixin/cp/api/WxCpTpService.java  |   4 -
 .../weixin/cp/api/WxCpUserService.java        |  12 --
 .../cp/api/impl/BaseWxCpServiceImpl.java      |  37 +++---
 .../cp/api/impl/BaseWxCpTpServiceImpl.java    |  69 ++++++------
 .../cp/api/impl/WxCpAgentServiceImpl.java     |  16 +--
 .../cp/api/impl/WxCpChatServiceImpl.java      |  16 +--
 .../api/impl/WxCpDepartmentServiceImpl.java   |  19 ++--
 .../cp/api/impl/WxCpMediaServiceImpl.java     |  20 ++--
 .../cp/api/impl/WxCpMenuServiceImpl.java      |  18 +--
 .../cp/api/impl/WxCpOAuth2ServiceImpl.java    |  14 ++-
 .../weixin/cp/api/impl/WxCpOaServiceImpl.java |  23 ++--
 .../impl/WxCpServiceApacheHttpClientImpl.java |   8 +-
 .../cp/api/impl/WxCpServiceJoddHttpImpl.java  |  13 ++-
 .../cp/api/impl/WxCpServiceOkHttpImpl.java    |  18 ++-
 .../cp/api/impl/WxCpServiceOnTpImpl.java      |  70 ++++++------
 .../cp/api/impl/WxCpTagServiceImpl.java       |  35 +++---
 .../cp/api/impl/WxCpTaskCardServiceImpl.java  |   6 +-
 .../WxCpTpServiceApacheHttpClientImpl.java    |   4 +-
 .../weixin/cp/api/impl/WxCpTpServiceImpl.java |  24 ++--
 .../cp/api/impl/WxCpUserServiceImpl.java      |  40 +++----
 .../weixin/cp/bean/WxCpAppChatMessage.java    |   2 +-
 .../weixin/cp/bean/WxCpXmlMessage.java        |   2 +-
 .../weixin/cp/config/WxCpConfigStorage.java   |  16 ++-
 .../cp/config/WxCpInMemoryConfigStorage.java  |   4 +-
 .../cp/config/WxCpJedisConfigStorage.java     |   3 +-
 .../weixin/cp/constant/WxCpApiPathConsts.java | 106 ++++++++++++++++++
 .../weixin/cp/{ => constant}/WxCpConsts.java  |   2 +-
 .../cp/api/impl/WxCpAgentServiceImplTest.java |   4 +-
 .../cp/api/impl/WxCpChatServiceImplTest.java  |   2 +-
 .../cp/api/impl/WxCpTagServiceImplTest.java   |   3 +-
 .../weixin/cp/bean/WxCpXmlMessageTest.java    |   2 +-
 .../weixin/cp/demo/WxCpDemoServer.java        |   2 +-
 42 files changed, 348 insertions(+), 310 deletions(-)
 create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
 rename weixin-java-cp/src/main/java/me/chanjar/weixin/cp/{ => constant}/WxCpConsts.java (99%)

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 7dad7b6c76..d57ca56c21 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
@@ -15,10 +15,6 @@
  * @author huansinho
  */
 public interface WxCpAgentService {
-  String GET_AGENT = "/cgi-bin/agent/get?agentid=%d";
-  String AGENT_SET = "/cgi-bin/agent/set";
-  String AGENT_LIST = "/cgi-bin/agent/list";
-
   /**
    * 
    * 获取企业号应用信息
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpChatService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpChatService.java
index 58ab329f01..741ee906d5 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpChatService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpChatService.java
@@ -12,10 +12,6 @@
  * @author gaigeshen
  */
 public interface WxCpChatService {
-  String APPCHAT_CREATE = "/cgi-bin/appchat/create";
-  String APPCHAT_UPDATE = "/cgi-bin/appchat/update";
-  String APPCHAT_GET_CHATID = "/cgi-bin/appchat/get?chatid=";
-  String APPCHAT_SEND = "/cgi-bin/appchat/send";
 
   @Deprecated
   String chatCreate(String name, String owner, List users, String chatId) throws WxErrorException;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java
index 8aa7ca353a..c86816b7f2 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpDepartmentService.java
@@ -14,10 +14,6 @@
  * @author Binary Wang
  */
 public interface WxCpDepartmentService {
-  String DEPARTMENT_CREATE = "/cgi-bin/department/create";
-  String DEPARTMENT_UPDATE = "/cgi-bin/department/update";
-  String DEPARTMENT_DELETE = "/cgi-bin/department/delete?id=%d";
-  String DEPARTMENT_LIST = "/cgi-bin/department/list";
 
   /**
    * 
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 67c67ec625..a51e04e175 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
@@ -16,10 +16,6 @@
  * @author Binary Wang
  */
 public interface WxCpMediaService {
-  String MEDIA_GET_URL = "/cgi-bin/media/get";
-  String MEDIA_UPLOAD_URL = "/cgi-bin/media/upload?type=";
-  String IMG_UPLOAD_URL = "/cgi-bin/media/uploadimg";
-  String JSSDK_MEDIA_GET_URL = "/cgi-bin/media/get/jssdk";
 
   /**
    * 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java
index 7c0a01e595..309b981211 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMenuService.java
@@ -12,9 +12,6 @@
  * @author Binary Wang
  */
 public interface WxCpMenuService {
-  String MENU_CREATE = "/cgi-bin/menu/create?agentid=%d";
-  String MENU_DELETE = "/cgi-bin/menu/delete?agentid=%d";
-  String MENU_GET = "/cgi-bin/menu/get?agentid=%d";
 
   /**
    * 
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 39d2163e7b..7c42ea63fc 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
@@ -13,9 +13,6 @@
  * @author Binary Wang
  */
 public interface WxCpOAuth2Service {
-  String URL_GET_USER_INFO = "/cgi-bin/user/getuserinfo?code=%s&agentid=%d";
-  String URL_GET_USER_DETAIL = "/cgi-bin/user/getuserdetail";
-  String URL_OAUTH_2_AUTHORIZE = "https://open.weixin.qq.com/connect/oauth2/authorize";
 
   /**
    * 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaService.java
index 5cca9e7788..c6f90d3e64 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaService.java
@@ -16,10 +16,6 @@
  * @date 2019-04-06 10:52
  */
 public interface WxCpOaService {
-  String GET_CHECKIN_DATA = "/cgi-bin/checkin/getcheckindata";
-  String GET_CHECKIN_OPTION = "/cgi-bin/checkin/getcheckinoption";
-  String GET_APPROVAL_DATA = "/cgi-bin/corp/getapprovaldata";
-  String GET_DIAL_RECORD = "/cgi-bin/dial/get_dial_record";
 
   /**
    * 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java
index 12ae987b1b..aeb7ff0956 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java
@@ -17,16 +17,6 @@
  * @author chanjaster
  */
 public interface WxCpService {
-  String GET_JSAPI_TICKET = "/cgi-bin/get_jsapi_ticket";
-  String GET_AGENT_CONFIG_TICKET = "/cgi-bin/ticket/get?&type=agent_config";
-  String MESSAGE_SEND = "/cgi-bin/message/send";
-  String GET_CALLBACK_IP = "/cgi-bin/getcallbackip";
-  String BATCH_REPLACE_PARTY = "/cgi-bin/batch/replaceparty";
-  String BATCH_REPLACE_USER = "/cgi-bin/batch/replaceuser";
-  String BATCH_GET_RESULT = "/cgi-bin/batch/getresult?jobid=";
-  String JSCODE_TO_SESSION_URL = "/cgi-bin/miniprogram/jscode2session";
-  String GET_TOKEN = "/cgi-bin/gettoken?&corpid=%s&corpsecret=%s";
-
   /**
    * 
    * 验证推送过来的消息的正确性
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java
index ee1b526d64..78f1d79139 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTagService.java
@@ -17,13 +17,6 @@
  * @author Binary Wang
  */
 public interface WxCpTagService {
-  String TAG_CREATE = "/cgi-bin/tag/create";
-  String TAG_UPDATE = "/cgi-bin/tag/update";
-  String TAG_DELETE = "/cgi-bin/tag/delete?tagid=%s";
-  String TAG_LIST = "/cgi-bin/tag/list";
-  String TAG_GET = "/cgi-bin/tag/get?tagid=%s";
-  String TAG_ADDTAGUSERS = "/cgi-bin/tag/addtagusers";
-  String TAG_DELTAGUSERS = "/cgi-bin/tag/deltagusers";
 
   /**
    * 创建标签.
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTaskCardService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTaskCardService.java
index b6ebdc1202..5bf50d36dc 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTaskCardService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTaskCardService.java
@@ -14,7 +14,6 @@
  * @date 2019-05-16
  */
 public interface WxCpTaskCardService {
-  String MESSAGE_UPDATE_TASKCARD = "/cgi-bin/message/update_taskcard";
 
   /**
    * 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java
index 6c52bcfde6..40ffcf55e2 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpTpService.java
@@ -15,10 +15,6 @@
  * @author zhenjun cai
  */
 public interface WxCpTpService {
-  String JSCODE_TO_SESSION_URL = "/cgi-bin/service/miniprogram/jscode2session";
-  String GET_CORP_TOKEN = "/cgi-bin/service/get_corp_token";
-  String GET_PERMANENT_CODE = "/cgi-bin/service/get_permanent_code";
-  String GET_SUITE_TOKEN = "/cgi-bin/service/get_suite_token";
 
   /**
    * 
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 4289ae94c7..4561ecb35c 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
@@ -17,18 +17,6 @@
  * @author Binary Wang
  */
 public interface WxCpUserService {
-  String URL_AUTHENTICATE = "/cgi-bin/user/authsucc?userid=";
-  String URL_USER_CREATE = "/cgi-bin/user/create";
-  String URL_USER_UPDATE = "/cgi-bin/user/update";
-  String URL_USER_DELETE = "/cgi-bin/user/delete?userid=";
-  String URL_USER_BATCH_DELETE = "/cgi-bin/user/batchdelete";
-  String URL_USER_GET = "/cgi-bin/user/get?userid=";
-  String URL_USER_LIST = "/cgi-bin/user/list?department_id=";
-  String URL_USER_SIMPLE_LIST = "/cgi-bin/user/simplelist?department_id=";
-  String URL_BATCH_INVITE = "/cgi-bin/batch/invite";
-  String URL_CONVERT_TO_OPENID = "/cgi-bin/user/convert_to_openid";
-  String URL_CONVERT_TO_USERID = "/cgi-bin/user/convert_to_userid";
-  String URL_GET_EXTERNAL_CONTACT = "/cgi-bin/crm/get_external_contact?external_userid=";
 
   /**
    * 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java
index e0bab1d90e..9db88b7c0e 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java
@@ -5,6 +5,7 @@
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
+import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.bean.WxJsapiSignature;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
@@ -33,6 +34,7 @@
 import me.chanjar.weixin.cp.bean.WxCpMessage;
 import me.chanjar.weixin.cp.bean.WxCpMessageSendResult;
 import me.chanjar.weixin.cp.config.WxCpConfigStorage;
+import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -41,12 +43,13 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.*;
+
 /**
  * @author chanjarster
  */
+@Slf4j
 public abstract class BaseWxCpServiceImpl implements WxCpService, RequestHttp {
-  protected final Logger log = LoggerFactory.getLogger(this.getClass());
-
   private WxCpUserService       userService       = new WxCpUserServiceImpl(this);
   private WxCpChatService       chatService       = new WxCpChatServiceImpl(this);
   private WxCpDepartmentService departmentService = new WxCpDepartmentServiceImpl(this);
@@ -90,7 +93,7 @@ public boolean checkSignature(String msgSignature, String timestamp, String nonc
       return SHA1.gen(this.configStorage.getToken(), timestamp, nonce, data)
         .equals(msgSignature);
     } catch (Exception e) {
-      this.log.error("Checking signature failed, and the reason is :" + e.getMessage());
+      log.error("Checking signature failed, and the reason is :" + e.getMessage());
       return false;
     }
   }
@@ -114,7 +117,7 @@ public String getAgentJsapiTicket(boolean forceRefresh) throws WxErrorException
     if (this.configStorage.isAgentJsapiTicketExpired()) {
       synchronized (this.globalAgentJsapiTicketRefreshLock) {
         if (this.configStorage.isAgentJsapiTicketExpired()) {
-          String responseContent = this.get(this.configStorage.getApiUrl(WxCpService.GET_AGENT_CONFIG_TICKET), null);
+          String responseContent = this.get(this.configStorage.getApiUrl(GET_AGENT_CONFIG_TICKET), null);
           JsonObject jsonObject = new JsonParser().parse(responseContent).getAsJsonObject();
           this.configStorage.updateAgentJsapiTicket(jsonObject.get("ticket").getAsString(),
             jsonObject.get("expires_in").getAsInt());
@@ -139,7 +142,7 @@ public String getJsapiTicket(boolean forceRefresh) throws WxErrorException {
     if (this.configStorage.isJsapiTicketExpired()) {
       synchronized (this.globalJsapiTicketRefreshLock) {
         if (this.configStorage.isJsapiTicketExpired()) {
-          String responseContent = this.get(this.configStorage.getApiUrl(WxCpService.GET_JSAPI_TICKET), null);
+          String responseContent = this.get(this.configStorage.getApiUrl(GET_JSAPI_TICKET), null);
           JsonObject tmpJsonObject = new JsonParser().parse(responseContent).getAsJsonObject();
           this.configStorage.updateJsapiTicket(tmpJsonObject.get("ticket").getAsString(),
             tmpJsonObject.get("expires_in").getAsInt());
@@ -180,7 +183,7 @@ public WxCpMessageSendResult messageSend(WxCpMessage message) throws WxErrorExce
       message.setAgentId(this.getWxCpConfigStorage().getAgentId());
     }
 
-    return WxCpMessageSendResult.fromJson(this.post(this.configStorage.getApiUrl(WxCpService.MESSAGE_SEND), message.toJson()));
+    return WxCpMessageSendResult.fromJson(this.post(this.configStorage.getApiUrl(MESSAGE_SEND), message.toJson()));
   }
 
   @Override
@@ -189,13 +192,13 @@ public WxCpMaJsCode2SessionResult jsCode2Session(String jsCode) throws WxErrorEx
     params.put("js_code", jsCode);
     params.put("grant_type", "authorization_code");
 
-    String result = this.get(this.configStorage.getApiUrl(JSCODE_TO_SESSION_URL), Joiner.on("&").withKeyValueSeparator("=").join(params));
+    String result = this.get(this.configStorage.getApiUrl(JSCODE_TO_SESSION), Joiner.on("&").withKeyValueSeparator("=").join(params));
     return WxCpMaJsCode2SessionResult.fromJson(result);
   }
 
   @Override
   public String[] getCallbackIp() throws WxErrorException {
-    String responseContent = get(this.configStorage.getApiUrl(WxCpService.GET_CALLBACK_IP), null);
+    String responseContent = get(this.configStorage.getApiUrl(GET_CALLBACK_IP), null);
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     JsonArray jsonArray = tmpJsonElement.getAsJsonObject().get("ip_list").getAsJsonArray();
     String[] ips = new String[jsonArray.size()];
@@ -226,7 +229,7 @@ public  T execute(RequestExecutor executor, String uri, E data) thro
         return this.executeInternal(executor, uri, data);
       } catch (WxErrorException e) {
         if (retryTimes + 1 > this.maxRetryTimes) {
-          this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
+          log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
           //最后一次重试失败后,直接抛出异常,不再等待
           throw new RuntimeException("微信服务端异常,超出重试次数");
         }
@@ -238,7 +241,7 @@ public  T execute(RequestExecutor executor, String uri, E data) thro
         if (error.getErrorCode() == -1) {
           int sleepMillis = this.retrySleepMillis * (1 << retryTimes);
           try {
-            this.log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
+            log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
             Thread.sleep(sleepMillis);
           } catch (InterruptedException e1) {
             Thread.currentThread().interrupt();
@@ -249,7 +252,7 @@ public  T execute(RequestExecutor executor, String uri, E data) thro
       }
     } while (retryTimes++ < this.maxRetryTimes);
 
-    this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
+    log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
     throw new RuntimeException("微信服务端异常,超出重试次数");
   }
 
@@ -265,7 +268,7 @@ protected  T executeInternal(RequestExecutor executor, String uri, E
 
     try {
       T result = executor.execute(uriWithAccessToken, data);
-      this.log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result);
+      log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result);
       return result;
     } catch (WxErrorException e) {
       WxError error = e.getError();
@@ -282,12 +285,12 @@ protected  T executeInternal(RequestExecutor executor, String uri, E
       }
 
       if (error.getErrorCode() != 0) {
-        this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error);
+        log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error);
         throw new WxErrorException(error, e);
       }
       return null;
     } catch (IOException e) {
-      this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage());
+      log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage());
       throw new RuntimeException(e);
     }
   }
@@ -339,19 +342,19 @@ public WxSessionManager getSessionManager() {
   public String replaceParty(String mediaId) throws WxErrorException {
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("media_id", mediaId);
-    return post(this.configStorage.getApiUrl(WxCpService.BATCH_REPLACE_PARTY), jsonObject.toString());
+    return post(this.configStorage.getApiUrl(BATCH_REPLACE_PARTY), jsonObject.toString());
   }
 
   @Override
   public String replaceUser(String mediaId) throws WxErrorException {
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("media_id", mediaId);
-    return post(this.configStorage.getApiUrl(WxCpService.BATCH_REPLACE_USER), jsonObject.toString());
+    return post(this.configStorage.getApiUrl(BATCH_REPLACE_USER), jsonObject.toString());
   }
 
   @Override
   public String getTaskResult(String joinId) throws WxErrorException {
-    String url = this.configStorage.getApiUrl(WxCpService.BATCH_GET_RESULT + joinId);
+    String url = this.configStorage.getApiUrl(BATCH_GET_RESULT + joinId);
     return get(url, null);
   }
 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImpl.java
index f3714516cf..92c6ac2985 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpTpServiceImpl.java
@@ -1,17 +1,9 @@
 package me.chanjar.weixin.cp.api.impl;
 
-import java.io.File;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import com.google.common.base.Joiner;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
-
+import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.WxType;
 import me.chanjar.weixin.common.bean.WxAccessToken;
 import me.chanjar.weixin.common.error.WxError;
@@ -22,34 +14,37 @@
 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.cp.api.WxCpService;
 import me.chanjar.weixin.cp.api.WxCpTpService;
 import me.chanjar.weixin.cp.bean.WxCpMaJsCode2SessionResult;
 import me.chanjar.weixin.cp.bean.WxCpTpCorp;
 import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
+import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * @author zhenjun cai
  */
+@Slf4j
 public abstract class BaseWxCpTpServiceImpl implements WxCpTpService, RequestHttp {
-  protected final Logger log = LoggerFactory.getLogger(this.getClass());
 
   /**
-   * 全局的是否正在刷新access token的锁
+   * 全局的是否正在刷新access token的锁.
    */
   protected final Object globalSuiteAccessTokenRefreshLock = new Object();
 
   /**
-   * 全局的是否正在刷新jsapi_ticket的锁
+   * 全局的是否正在刷新jsapi_ticket的锁.
    */
   protected final Object globalSuiteTicketRefreshLock = new Object();
 
-
   protected WxCpTpConfigStorage configStorage;
 
-
   /**
-   * 临时文件目录
+   * 临时文件目录.
    */
   private File tmpDirFile;
   private int retrySleepMillis = 1000;
@@ -61,7 +56,7 @@ public boolean checkSignature(String msgSignature, String timestamp, String nonc
       return SHA1.gen(this.configStorage.getToken(), timestamp, nonce, data)
         .equals(msgSignature);
     } catch (Exception e) {
-      this.log.error("Checking signature failed, and the reason is :" + e.getMessage());
+      log.error("Checking signature failed, and the reason is :" + e.getMessage());
       return false;
     }
   }
@@ -83,11 +78,11 @@ public String getSuiteTicket(boolean forceRefresh) throws WxErrorException {
 //      this.configStorage.expireSuiteTicket();
 //    }
 
-	if (this.configStorage.isSuiteTicketExpired()) {
-//	   本地suite ticket 不存在或者过期	
-	  WxError wxError = WxError.fromJson("{\"errcode\":40085, \"errmsg\":\"invaild suite ticket\"}", WxType.CP);
-	  throw new WxErrorException(wxError);
-	}
+    if (this.configStorage.isSuiteTicketExpired()) {
+      // 本地suite ticket 不存在或者过期
+      WxError wxError = WxError.fromJson("{\"errcode\":40085, \"errmsg\":\"invaild suite ticket\"}", WxType.CP);
+      throw new WxErrorException(wxError);
+    }
     return this.configStorage.getSuiteTicket();
   }
 
@@ -98,28 +93,28 @@ public WxCpMaJsCode2SessionResult jsCode2Session(String jsCode) throws WxErrorEx
     params.put("js_code", jsCode);
     params.put("grant_type", "authorization_code");
 
-    String result = this.get(configStorage.getApiUrl(JSCODE_TO_SESSION_URL), Joiner.on("&").withKeyValueSeparator("=").join(params));
+    String result = this.get(configStorage.getApiUrl(WxCpApiPathConsts.Tp.JSCODE_TO_SESSION), Joiner.on("&").withKeyValueSeparator("=").join(params));
     return WxCpMaJsCode2SessionResult.fromJson(result);
   }
 
 
   @Override
   public WxAccessToken getCorpToken(String authCorpid, String permanentCode) throws WxErrorException {
-	JsonObject jsonObject = new JsonObject();
-	jsonObject.addProperty("auth_corpid", authCorpid);
-	jsonObject.addProperty("permanent_code", permanentCode);
-	String result = post(configStorage.getApiUrl(GET_CORP_TOKEN), jsonObject.toString());
-	
-	return WxAccessToken.fromJson(result);
+    JsonObject jsonObject = new JsonObject();
+    jsonObject.addProperty("auth_corpid", authCorpid);
+    jsonObject.addProperty("permanent_code", permanentCode);
+    String result = post(configStorage.getApiUrl(WxCpApiPathConsts.Tp.GET_CORP_TOKEN), jsonObject.toString());
+
+    return WxAccessToken.fromJson(result);
   }
-  
+
 
   @Override
   public WxCpTpCorp getPermanentCode(String authCode) throws WxErrorException {
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("auth_code", authCode);
 
-    String result = post(configStorage.getApiUrl(GET_PERMANENT_CODE), jsonObject.toString());
+    String result = post(configStorage.getApiUrl(WxCpApiPathConsts.Tp.GET_PERMANENT_CODE), jsonObject.toString());
     jsonObject = new JsonParser().parse(result).getAsJsonObject();
     WxCpTpCorp wxCpTpCorp = WxCpTpCorp.fromJson(jsonObject.get("auth_corp_info").getAsString());
     wxCpTpCorp.setPermanentCode(jsonObject.get("permanent_code").getAsString());
@@ -147,7 +142,7 @@ public  T execute(RequestExecutor executor, String uri, E data) thro
         return this.executeInternal(executor, uri, data);
       } catch (WxErrorException e) {
         if (retryTimes + 1 > this.maxRetryTimes) {
-          this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
+          log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
           //最后一次重试失败后,直接抛出异常,不再等待
           throw new RuntimeException("微信服务端异常,超出重试次数");
         }
@@ -159,7 +154,7 @@ public  T execute(RequestExecutor executor, String uri, E data) thro
         if (error.getErrorCode() == -1) {
           int sleepMillis = this.retrySleepMillis * (1 << retryTimes);
           try {
-            this.log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
+            log.debug("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
             Thread.sleep(sleepMillis);
           } catch (InterruptedException e1) {
             Thread.currentThread().interrupt();
@@ -170,7 +165,7 @@ public  T execute(RequestExecutor executor, String uri, E data) thro
       }
     } while (retryTimes++ < this.maxRetryTimes);
 
-    this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
+    log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
     throw new RuntimeException("微信服务端异常,超出重试次数");
   }
 
@@ -186,7 +181,7 @@ protected  T executeInternal(RequestExecutor executor, String uri, E
 
     try {
       T result = executor.execute(uriWithAccessToken, data);
-      this.log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result);
+      log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result);
       return result;
     } catch (WxErrorException e) {
       WxError error = e.getError();
@@ -201,12 +196,12 @@ protected  T executeInternal(RequestExecutor executor, String uri, E
       }
 
       if (error.getErrorCode() != 0) {
-        this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error);
+        log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error);
         throw new WxErrorException(error, e);
       }
       return null;
     } catch (IOException e) {
-      this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage());
+      log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage());
       throw new RuntimeException(e);
     }
   }
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 2dc5ca8755..6a9b774691 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
@@ -3,6 +3,7 @@
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
 import com.google.gson.reflect.TypeToken;
+import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.cp.api.WxCpAgentService;
@@ -12,6 +13,8 @@
 
 import java.util.List;
 
+import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Agent.*;
+
 
 /**
  * 
@@ -21,14 +24,11 @@
  *
  * @author huansinho
  */
+@RequiredArgsConstructor
 public class WxCpAgentServiceImpl implements WxCpAgentService {
   private static final JsonParser JSON_PARSER = new JsonParser();
 
-  private WxCpService mainService;
-
-  public WxCpAgentServiceImpl(WxCpService mainService) {
-    this.mainService = mainService;
-  }
+  private final WxCpService mainService;
 
   @Override
   public WxCpAgent get(Integer agentId) throws WxErrorException {
@@ -36,13 +36,13 @@ public WxCpAgent get(Integer agentId) throws WxErrorException {
       throw new IllegalArgumentException("缺少agentid参数");
     }
 
-    String responseContent = this.mainService.get(String.format(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpAgentService.GET_AGENT), agentId), null);
+    String responseContent = this.mainService.get(String.format(this.mainService.getWxCpConfigStorage().getApiUrl(AGENT_GET), agentId), null);
     return WxCpAgent.fromJson(responseContent);
   }
 
   @Override
   public void set(WxCpAgent agentInfo) throws WxErrorException {
-    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpAgentService.AGENT_SET);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(AGENT_SET);
     String responseContent = this.mainService.post(url, agentInfo.toJson());
     JsonObject jsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject();
     if (jsonObject.get("errcode").getAsInt() != 0) {
@@ -52,7 +52,7 @@ public void set(WxCpAgent agentInfo) throws WxErrorException {
 
   @Override
   public List list() throws WxErrorException {
-    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpAgentService.AGENT_LIST);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(AGENT_LIST);
     String responseContent = this.mainService.get(url, null);
     JsonObject jsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject();
     if (jsonObject.get("errcode").getAsInt() != 0) {
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java
index 1bf809502b..bd5baf01dd 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImpl.java
@@ -1,12 +1,14 @@
 package me.chanjar.weixin.cp.api.impl;
 
 import com.google.gson.JsonParser;
+import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 import me.chanjar.weixin.cp.api.WxCpChatService;
 import me.chanjar.weixin.cp.api.WxCpService;
 import me.chanjar.weixin.cp.bean.WxCpAppChatMessage;
 import me.chanjar.weixin.cp.bean.WxCpChat;
+import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 import org.apache.commons.lang3.StringUtils;
 
@@ -14,24 +16,18 @@
 import java.util.List;
 import java.util.Map;
 
+import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Chat.*;
+
 /**
  * 群聊服务实现.
  *
  * @author gaigeshen
  */
+@RequiredArgsConstructor
 public class WxCpChatServiceImpl implements WxCpChatService {
   private static final JsonParser JSON_PARSER = new JsonParser();
   private final WxCpService cpService;
 
-  /**
-   * 创建群聊服务实现的实例.
-   *
-   * @param cpService 企业微信的服务
-   */
-  WxCpChatServiceImpl(WxCpService cpService) {
-    this.cpService = cpService;
-  }
-
   @Override
   public String chatCreate(String name, String owner, List users, String chatId) throws WxErrorException {
     Map data = new HashMap<>(4);
@@ -98,7 +94,7 @@ public WxCpChat get(String chatId) throws WxErrorException {
 
   @Override
   public void sendMsg(WxCpAppChatMessage message) throws WxErrorException {
-    this.cpService.post(this.cpService.getWxCpConfigStorage().getApiUrl(WxCpChatService.APPCHAT_SEND), message.toJson());
+    this.cpService.post(this.cpService.getWxCpConfigStorage().getApiUrl(APPCHAT_SEND), message.toJson());
   }
 
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java
index ce6f02ae5f..fb2224e335 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpDepartmentServiceImpl.java
@@ -3,15 +3,19 @@
 import com.google.gson.JsonElement;
 import com.google.gson.JsonParser;
 import com.google.gson.reflect.TypeToken;
+import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.json.GsonHelper;
 import me.chanjar.weixin.cp.api.WxCpDepartmentService;
 import me.chanjar.weixin.cp.api.WxCpService;
 import me.chanjar.weixin.cp.bean.WxCpDepart;
+import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
 import java.util.List;
 
+import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Department.*;
+
 /**
  * 
  *  部门管理接口
@@ -20,16 +24,13 @@
  *
  * @author Binary Wang
  */
+@RequiredArgsConstructor
 public class WxCpDepartmentServiceImpl implements WxCpDepartmentService {
-  private WxCpService mainService;
-
-  public WxCpDepartmentServiceImpl(WxCpService mainService) {
-    this.mainService = mainService;
-  }
+  private final WxCpService mainService;
 
   @Override
   public Long create(WxCpDepart depart) throws WxErrorException {
-    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpDepartmentService.DEPARTMENT_CREATE);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_CREATE);
     String responseContent = this.mainService.post(url, depart.toJson());
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return GsonHelper.getAsLong(tmpJsonElement.getAsJsonObject().get("id"));
@@ -37,19 +38,19 @@ public Long create(WxCpDepart depart) throws WxErrorException {
 
   @Override
   public void update(WxCpDepart group) throws WxErrorException {
-    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpDepartmentService.DEPARTMENT_UPDATE);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_UPDATE);
     this.mainService.post(url, group.toJson());
   }
 
   @Override
   public void delete(Long departId) throws WxErrorException {
-    String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpDepartmentService.DEPARTMENT_DELETE), departId);
+    String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_DELETE), departId);
     this.mainService.get(url, null);
   }
 
   @Override
   public List list(Long id) throws WxErrorException {
-    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpDepartmentService.DEPARTMENT_LIST);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_LIST);
     if (id != null) {
       url += "?id=" + id;
     }
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 fa31a033ba..05e13cfc8a 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,19 +1,22 @@
 package me.chanjar.weixin.cp.api.impl;
 
+import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.fs.FileUtils;
 import me.chanjar.weixin.common.util.http.BaseMediaDownloadRequestExecutor;
 import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
-import me.chanjar.weixin.cp.WxCpConsts;
 import me.chanjar.weixin.cp.api.WxCpMediaService;
 import me.chanjar.weixin.cp.api.WxCpService;
+import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
 
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.UUID;
 
+import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Media.*;
+
 /**
  * 
  * 媒体管理接口.
@@ -22,12 +25,9 @@
  *
  * @author Binary Wang
  */
+@RequiredArgsConstructor
 public class WxCpMediaServiceImpl implements WxCpMediaService {
-  private WxCpService mainService;
-
-  public WxCpMediaServiceImpl(WxCpService mainService) {
-    this.mainService = mainService;
-  }
+  private final WxCpService mainService;
 
   @Override
   public WxMediaUploadResult upload(String mediaType, String fileType, InputStream inputStream)
@@ -38,7 +38,7 @@ public WxMediaUploadResult upload(String mediaType, String fileType, InputStream
   @Override
   public WxMediaUploadResult upload(String mediaType, File file) throws WxErrorException {
     return this.mainService.execute(MediaUploadRequestExecutor.create(this.mainService.getRequestHttp()),
-      this.mainService.getWxCpConfigStorage().getApiUrl(MEDIA_UPLOAD_URL + mediaType), file);
+      this.mainService.getWxCpConfigStorage().getApiUrl(MEDIA_UPLOAD + mediaType), file);
   }
 
   @Override
@@ -46,7 +46,7 @@ public File download(String mediaId) throws WxErrorException {
     return this.mainService.execute(
       BaseMediaDownloadRequestExecutor.create(this.mainService.getRequestHttp(),
         this.mainService.getWxCpConfigStorage().getTmpDirFile()),
-      this.mainService.getWxCpConfigStorage().getApiUrl(MEDIA_GET_URL), "media_id=" + mediaId);
+      this.mainService.getWxCpConfigStorage().getApiUrl(MEDIA_GET), "media_id=" + mediaId);
   }
 
   @Override
@@ -54,13 +54,13 @@ public File getJssdkFile(String mediaId) throws WxErrorException {
     return this.mainService.execute(
       BaseMediaDownloadRequestExecutor.create(this.mainService.getRequestHttp(),
         this.mainService.getWxCpConfigStorage().getTmpDirFile()),
-      this.mainService.getWxCpConfigStorage().getApiUrl(JSSDK_MEDIA_GET_URL), "media_id=" + mediaId);
+      this.mainService.getWxCpConfigStorage().getApiUrl(JSSDK_MEDIA_GET), "media_id=" + mediaId);
   }
 
   @Override
   public String uploadImg(File file) throws WxErrorException {
     final WxMediaUploadResult result = this.mainService
-      .execute(MediaUploadRequestExecutor.create(this.mainService.getRequestHttp()), this.mainService.getWxCpConfigStorage().getApiUrl(IMG_UPLOAD_URL), file);
+      .execute(MediaUploadRequestExecutor.create(this.mainService.getRequestHttp()), this.mainService.getWxCpConfigStorage().getApiUrl(IMG_UPLOAD), file);
     return result.getUrl();
   }
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java
index a03d600145..85abe71f45 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMenuServiceImpl.java
@@ -1,12 +1,15 @@
 package me.chanjar.weixin.cp.api.impl;
 
+import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.bean.menu.WxMenu;
 import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.cp.WxCpConsts;
 import me.chanjar.weixin.cp.api.WxCpMenuService;
 import me.chanjar.weixin.cp.api.WxCpService;
+import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
+import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Menu.*;
+
 /**
  * 
  * 菜单管理相关接口.
@@ -15,12 +18,9 @@
  *
  * @author Binary Wang
  */
+@RequiredArgsConstructor
 public class WxCpMenuServiceImpl implements WxCpMenuService {
-  private WxCpService mainService;
-
-  public WxCpMenuServiceImpl(WxCpService mainService) {
-    this.mainService = mainService;
-  }
+  private final WxCpService mainService;
 
   @Override
   public void create(WxMenu menu) throws WxErrorException {
@@ -29,7 +29,7 @@ public void create(WxMenu menu) throws WxErrorException {
 
   @Override
   public void create(Integer agentId, WxMenu menu) throws WxErrorException {
-    String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpMenuService.MENU_CREATE), agentId);
+    String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(MENU_CREATE), agentId);
     this.mainService.post(url, menu.toJson());
   }
 
@@ -40,7 +40,7 @@ public void delete() throws WxErrorException {
 
   @Override
   public void delete(Integer agentId) throws WxErrorException {
-    String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpMenuService.MENU_DELETE), agentId);
+    String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(MENU_DELETE), agentId);
     this.mainService.get(url, null);
   }
 
@@ -51,7 +51,7 @@ public WxMenu get() throws WxErrorException {
 
   @Override
   public WxMenu get(Integer agentId) throws WxErrorException {
-    String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpMenuService.MENU_GET), agentId);
+    String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(MENU_GET), agentId);
     try {
       String resultContent = this.mainService.get(url, null);
       return WxCpGsonBuilder.create().fromJson(resultContent, WxMenu.class);
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 aedc9ab24d..2005bc36eb 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.JsonObject;
 import com.google.gson.JsonParser;
 import lombok.AllArgsConstructor;
+import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.api.WxConsts;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.URIUtil;
@@ -12,10 +13,13 @@
 import me.chanjar.weixin.cp.api.WxCpService;
 import me.chanjar.weixin.cp.bean.WxCpOauth2UserInfo;
 import me.chanjar.weixin.cp.bean.WxCpUserDetail;
+import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
+import static me.chanjar.weixin.common.api.WxConsts.OAuth2Scope.*;
 import static me.chanjar.weixin.common.api.WxConsts.OAuth2Scope.SNSAPI_PRIVATEINFO;
 import static me.chanjar.weixin.common.api.WxConsts.OAuth2Scope.SNSAPI_USERINFO;
+import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.OAuth2.*;
 
 /**
  * 
@@ -25,7 +29,7 @@
  *
  * @author Binary Wang
  */
-@AllArgsConstructor
+@RequiredArgsConstructor
 public class WxCpOAuth2ServiceImpl implements WxCpOAuth2Service {
   private final WxCpService mainService;
 
@@ -39,12 +43,12 @@ public String buildAuthorizationUrl(String state) {
 
   @Override
   public String buildAuthorizationUrl(String redirectUri, String state) {
-    return this.buildAuthorizationUrl(redirectUri, state, WxConsts.OAuth2Scope.SNSAPI_BASE);
+    return this.buildAuthorizationUrl(redirectUri, state, SNSAPI_BASE);
   }
 
   @Override
   public String buildAuthorizationUrl(String redirectUri, String state, String scope) {
-    StringBuilder url = new StringBuilder(WxCpOAuth2Service.URL_OAUTH_2_AUTHORIZE);
+    StringBuilder url = new StringBuilder(URL_OAUTH2_AUTHORIZE);
     url.append("?appid=").append(this.mainService.getWxCpConfigStorage().getCorpId());
     url.append("&redirect_uri=").append(URIUtil.encodeURIComponent(redirectUri));
     url.append("&response_type=code");
@@ -69,7 +73,7 @@ public WxCpOauth2UserInfo getUserInfo(String code) throws WxErrorException {
 
   @Override
   public WxCpOauth2UserInfo getUserInfo(Integer agentId, String code) throws WxErrorException {
-    String responseText = this.mainService.get(String.format(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpOAuth2Service.URL_GET_USER_INFO), code, agentId), null);
+    String responseText = this.mainService.get(String.format(this.mainService.getWxCpConfigStorage().getApiUrl(GET_USER_INFO), code, agentId), null);
     JsonElement je = new JsonParser().parse(responseText);
     JsonObject jo = je.getAsJsonObject();
 
@@ -86,7 +90,7 @@ public WxCpOauth2UserInfo getUserInfo(Integer agentId, String code) throws WxErr
   public WxCpUserDetail getUserDetail(String userTicket) throws WxErrorException {
     JsonObject param = new JsonObject();
     param.addProperty("user_ticket", userTicket);
-    String responseText = this.mainService.post(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpOAuth2Service.URL_GET_USER_DETAIL), param.toString());
+    String responseText = this.mainService.post(this.mainService.getWxCpConfigStorage().getApiUrl(GET_USER_DETAIL), param.toString());
     return WxCpGsonBuilder.create().fromJson(responseText, WxCpUserDetail.class);
   }
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java
index c0f6ddaab6..5d7d758c08 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java
@@ -5,6 +5,7 @@
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
 import com.google.gson.reflect.TypeToken;
+import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.cp.api.WxCpOaService;
 import me.chanjar.weixin.cp.api.WxCpService;
@@ -12,25 +13,25 @@
 import me.chanjar.weixin.cp.bean.WxCpCheckinData;
 import me.chanjar.weixin.cp.bean.WxCpCheckinOption;
 import me.chanjar.weixin.cp.bean.WxCpDialRecord;
+import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
 import java.util.Date;
 import java.util.List;
 
+import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Oa.*;
+
 /**
  * @author Element
  * @date 2019-04-06 11:20
  */
+@RequiredArgsConstructor
 public class WxCpOaServiceImpl implements WxCpOaService {
-  private WxCpService mainService;
-
-  public WxCpOaServiceImpl(WxCpService mainService) {
-    this.mainService = mainService;
-  }
+  private final WxCpService mainService;
 
   @Override
-  public List getCheckinData(Integer openCheckinDataType, Date startTime, Date endTime, List userIdList) throws WxErrorException {
-
+  public List getCheckinData(Integer openCheckinDataType, Date startTime, Date endTime,
+                                              List userIdList) throws WxErrorException {
     if (startTime == null || endTime == null) {
       throw new RuntimeException("starttime and endtime can't be null");
     }
@@ -59,7 +60,7 @@ public List getCheckinData(Integer openCheckinDataType, Date st
 
     jsonObject.add("useridlist", jsonArray);
 
-    String responseContent = this.mainService.post(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpOaService.GET_CHECKIN_DATA), jsonObject.toString());
+    String responseContent = this.mainService.post(this.mainService.getWxCpConfigStorage().getApiUrl(GET_CHECKIN_DATA), jsonObject.toString());
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return WxCpGsonBuilder.create()
       .fromJson(
@@ -88,7 +89,7 @@ public List getCheckinOption(Date datetime, List user
     jsonObject.addProperty("datetime", datetime.getTime() / 1000L);
     jsonObject.add("useridlist", jsonArray);
 
-    String responseContent = this.mainService.post(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpOaService.GET_CHECKIN_OPTION), jsonObject.toString());
+    String responseContent = this.mainService.post(this.mainService.getWxCpConfigStorage().getApiUrl(GET_CHECKIN_OPTION), jsonObject.toString());
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
 
     return WxCpGsonBuilder.create()
@@ -108,7 +109,7 @@ public WxCpApprovalDataResult getApprovalData(Date startTime, Date endTime, Long
       jsonObject.addProperty("next_spnum", nextSpnum);
     }
 
-    String responseContent = this.mainService.post(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpOaService.GET_APPROVAL_DATA), jsonObject.toString());
+    String responseContent = this.mainService.post(this.mainService.getWxCpConfigStorage().getApiUrl(GET_APPROVAL_DATA), jsonObject.toString());
     return WxCpGsonBuilder.create().fromJson(responseContent, WxCpApprovalDataResult.class);
   }
 
@@ -140,7 +141,7 @@ public List getDialRecord(Date startTime, Date endTime, Integer
       jsonObject.addProperty("end_time", endtimestamp);
     }
 
-    String responseContent = this.mainService.post(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpOaService.GET_DIAL_RECORD), jsonObject.toString());
+    String responseContent = this.mainService.post(this.mainService.getWxCpConfigStorage().getApiUrl(GET_DIAL_RECORD), jsonObject.toString());
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
 
     return WxCpGsonBuilder.create()
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java
index 6dea258b99..d181af6749 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java
@@ -8,8 +8,8 @@
 import me.chanjar.weixin.common.util.http.HttpType;
 import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
 import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
-import me.chanjar.weixin.cp.api.WxCpService;
 import me.chanjar.weixin.cp.config.WxCpConfigStorage;
+import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
 import org.apache.http.client.methods.CloseableHttpResponse;
@@ -23,8 +23,8 @@
  * @author someone
  */
 public class WxCpServiceApacheHttpClientImpl extends BaseWxCpServiceImpl {
-  protected CloseableHttpClient httpClient;
-  protected HttpHost httpProxy;
+  private CloseableHttpClient httpClient;
+  private HttpHost httpProxy;
 
   @Override
   public CloseableHttpClient getRequestHttpClient() {
@@ -48,7 +48,7 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
     }
 
     synchronized (this.globalAccessTokenRefreshLock) {
-      String url = String.format(this.configStorage.getApiUrl(WxCpService.GET_TOKEN), this.configStorage.getCorpId(), this.configStorage.getCorpSecret());
+      String url = String.format(this.configStorage.getApiUrl(WxCpApiPathConsts.GET_TOKEN), this.configStorage.getCorpId(), this.configStorage.getCorpSecret());
 
       try {
         HttpGet httpGet = new HttpGet(url);
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java
index f1c5c8419a..cc76e9cf4c 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java
@@ -10,16 +10,15 @@
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.HttpType;
-import me.chanjar.weixin.cp.api.WxCpService;
 import me.chanjar.weixin.cp.config.WxCpConfigStorage;
+import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
 
 /**
  * @author someone
  */
 public class WxCpServiceJoddHttpImpl extends BaseWxCpServiceImpl {
-  protected HttpConnectionProvider httpClient;
-  protected ProxyInfo httpProxy;
-
+  private HttpConnectionProvider httpClient;
+  private ProxyInfo httpProxy;
 
   @Override
   public HttpConnectionProvider getRequestHttpClient() {
@@ -43,7 +42,8 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
     }
 
     synchronized (this.globalAccessTokenRefreshLock) {
-      HttpRequest request = HttpRequest.get(String.format(this.configStorage.getApiUrl(WxCpService.GET_TOKEN), this.configStorage.getCorpId(), this.configStorage.getCorpSecret()));
+      HttpRequest request = HttpRequest.get(String.format(this.configStorage.getApiUrl(WxCpApiPathConsts.GET_TOKEN),
+        this.configStorage.getCorpId(), this.configStorage.getCorpSecret()));
       if (this.httpProxy != null) {
         httpClient.useProxy(this.httpProxy);
       }
@@ -64,7 +64,8 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
   @Override
   public void initHttp() {
     if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) {
-      httpProxy = new ProxyInfo(ProxyInfo.ProxyType.HTTP, configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword());
+      httpProxy = new ProxyInfo(ProxyInfo.ProxyType.HTTP, configStorage.getHttpProxyHost(),
+        configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword());
     }
 
     httpClient = JoddHttp.httpConnectionProvider;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java
index 4280174dc4..596dc0608e 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java
@@ -1,25 +1,23 @@
 package me.chanjar.weixin.cp.api.impl;
 
+import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.WxType;
 import me.chanjar.weixin.common.bean.WxAccessToken;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.HttpType;
 import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
-import me.chanjar.weixin.cp.api.WxCpService;
 import me.chanjar.weixin.cp.config.WxCpConfigStorage;
-import okhttp3.Authenticator;
-import okhttp3.Credentials;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.Response;
-import okhttp3.Route;
+import okhttp3.*;
 
 import java.io.IOException;
 
+import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.GET_TOKEN;
+
 /**
  * @author someone
  */
+@Slf4j
 public class WxCpServiceOkHttpImpl extends BaseWxCpServiceImpl {
   private OkHttpClient httpClient;
   private OkHttpProxyInfo httpProxy;
@@ -50,7 +48,7 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
       OkHttpClient client = getRequestHttpClient();
       //请求的request
       Request request = new Request.Builder()
-        .url(String.format(this.configStorage.getApiUrl(WxCpService.GET_TOKEN), this.configStorage.getCorpId(), this.configStorage.getCorpSecret()))
+        .url(String.format(this.configStorage.getApiUrl(GET_TOKEN), this.configStorage.getCorpId(), this.configStorage.getCorpSecret()))
         .get()
         .build();
       String resultContent = null;
@@ -58,7 +56,7 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
         Response response = client.newCall(request).execute();
         resultContent = response.body().string();
       } catch (IOException e) {
-        this.log.error(e.getMessage(), e);
+        log.error(e.getMessage(), e);
       }
 
       WxError error = WxError.fromJson(resultContent, WxType.CP);
@@ -74,7 +72,7 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
 
   @Override
   public void initHttp() {
-    this.log.debug("WxCpServiceOkHttpImpl initHttp");
+    log.debug("WxCpServiceOkHttpImpl initHttp");
     //设置代理
     if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) {
       httpProxy = OkHttpProxyInfo.httpProxy(configStorage.getHttpProxyHost(),
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOnTpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOnTpImpl.java
index 1b7a67c6ea..35eab626a7 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOnTpImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOnTpImpl.java
@@ -1,37 +1,33 @@
-package me.chanjar.weixin.cp.api.impl;
-
-import me.chanjar.weixin.common.bean.WxAccessToken;
-import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.cp.api.WxCpTpService;
-
-/**
- * 
- *  默认接口实现类,使用apache httpclient实现,配合第三方应用service使用
- * Created by zhenjun cai.
- * 
- * - * @author Binary Wang - */ -public class WxCpServiceOnTpImpl extends WxCpServiceApacheHttpClientImpl { - //第三方应用service - WxCpTpService wxCpTpService; - - public void setWxCpTpService(WxCpTpService wxCpTpService) { - this.wxCpTpService = wxCpTpService; - } - - @Override - public String getAccessToken(boolean forceRefresh) throws WxErrorException { - if (!this.configStorage.isAccessTokenExpired() && !forceRefresh) { - return this.configStorage.getAccessToken(); - } - //access token通过第三方应用service获取 - //corpSecret对应企业永久授权码 - WxAccessToken accessToken = wxCpTpService.getCorpToken(this.configStorage.getCorpId(), this.configStorage.getCorpSecret()); - - this.configStorage.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); - return this.configStorage.getAccessToken(); - } - - -} +package me.chanjar.weixin.cp.api.impl; + +import lombok.RequiredArgsConstructor; +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.cp.api.WxCpTpService; + +/** + *
+ *  默认接口实现类,使用apache httpclient实现,配合第三方应用service使用
+ * Created by zhenjun cai.
+ * 
+ * + * @author zhenjun cai + */ +@RequiredArgsConstructor +public class WxCpServiceOnTpImpl extends WxCpServiceApacheHttpClientImpl { + private final WxCpTpService wxCpTpService; + + @Override + public String getAccessToken(boolean forceRefresh) throws WxErrorException { + if (!this.configStorage.isAccessTokenExpired() && !forceRefresh) { + return this.configStorage.getAccessToken(); + } + //access token通过第三方应用service获取 + //corpSecret对应企业永久授权码 + WxAccessToken accessToken = wxCpTpService.getCorpToken(this.configStorage.getCorpId(), this.configStorage.getCorpSecret()); + + this.configStorage.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); + return this.configStorage.getAccessToken(); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java index ee0db6da9f..d0e97c6ec2 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImpl.java @@ -1,11 +1,8 @@ package me.chanjar.weixin.cp.api.impl; -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.*; import com.google.gson.reflect.TypeToken; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.cp.api.WxCpService; import me.chanjar.weixin.cp.api.WxCpTagService; @@ -13,10 +10,15 @@ import me.chanjar.weixin.cp.bean.WxCpTagAddOrRemoveUsersResult; import me.chanjar.weixin.cp.bean.WxCpTagGetResult; import me.chanjar.weixin.cp.bean.WxCpUser; +import me.chanjar.weixin.cp.constant.WxCpApiPathConsts; import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; import java.util.List; +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Tag.*; +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Tag.TAG_CREATE; +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Tag.TAG_UPDATE; + /** *
  *  标签管理接口.
@@ -25,18 +27,15 @@
  *
  * @author Binary Wang
  */
+@RequiredArgsConstructor
 public class WxCpTagServiceImpl implements WxCpTagService {
-  private WxCpService mainService;
-
-  public WxCpTagServiceImpl(WxCpService mainService) {
-    this.mainService = mainService;
-  }
+  private final WxCpService mainService;
 
   @Override
   public String create(String tagName) throws WxErrorException {
     JsonObject o = new JsonObject();
     o.addProperty("tagname", tagName);
-    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpTagService.TAG_CREATE);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(TAG_CREATE);
     String responseContent = this.mainService.post(url, o.toString());
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return tmpJsonElement.getAsJsonObject().get("tagid").getAsString();
@@ -44,7 +43,7 @@ public String create(String tagName) throws WxErrorException {
 
   @Override
   public void update(String tagId, String tagName) throws WxErrorException {
-    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpTagService.TAG_UPDATE);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(TAG_UPDATE);
     JsonObject o = new JsonObject();
     o.addProperty("tagid", tagId);
     o.addProperty("tagname", tagName);
@@ -53,13 +52,13 @@ public void update(String tagId, String tagName) throws WxErrorException {
 
   @Override
   public void delete(String tagId) throws WxErrorException {
-    String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpTagService.TAG_DELETE), tagId);
+    String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(TAG_DELETE), tagId);
     this.mainService.get(url, null);
   }
 
   @Override
   public List listAll() throws WxErrorException {
-    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpTagService.TAG_LIST);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(TAG_LIST);
     String responseContent = this.mainService.get(url, null);
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return WxCpGsonBuilder.create()
@@ -72,7 +71,7 @@ public List listAll() throws WxErrorException {
 
   @Override
   public List listUsersByTagId(String tagId) throws WxErrorException {
-    String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpTagService.TAG_GET), tagId);
+    String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(TAG_GET), tagId);
     String responseContent = this.mainService.get(url, null);
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return WxCpGsonBuilder.create()
@@ -85,7 +84,7 @@ public List listUsersByTagId(String tagId) throws WxErrorException {
 
   @Override
   public WxCpTagAddOrRemoveUsersResult addUsers2Tag(String tagId, List userIds, List partyIds) throws WxErrorException {
-    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpTagService.TAG_ADDTAGUSERS);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(TAG_ADD_TAG_USERS);
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("tagid", tagId);
     this.addUserIdsAndPartyIdsToJson(userIds, partyIds, jsonObject);
@@ -95,7 +94,7 @@ public WxCpTagAddOrRemoveUsersResult addUsers2Tag(String tagId, List use
 
   @Override
   public WxCpTagAddOrRemoveUsersResult removeUsersFromTag(String tagId, List userIds, List partyIds) throws WxErrorException {
-    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpTagService.TAG_DELTAGUSERS);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(TAG_DEL_TAG_USERS);
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("tagid", tagId);
     this.addUserIdsAndPartyIdsToJson(userIds, partyIds, jsonObject);
@@ -127,7 +126,7 @@ public WxCpTagGetResult get(String tagId) throws WxErrorException {
       throw new IllegalArgumentException("缺少tagId参数");
     }
 
-    String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpTagService.TAG_GET), tagId);
+    String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(TAG_GET), tagId);
     String responseContent = this.mainService.get(url, null);
     return WxCpTagGetResult.fromJson(responseContent);
   }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTaskCardServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTaskCardServiceImpl.java
index a2efabb497..97530a6e9d 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTaskCardServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTaskCardServiceImpl.java
@@ -3,14 +3,16 @@
 import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.json.WxGsonBuilder;
-import me.chanjar.weixin.cp.WxCpConsts;
 import me.chanjar.weixin.cp.api.WxCpService;
 import me.chanjar.weixin.cp.api.WxCpTaskCardService;
+import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
 
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.TaskCard.*;
+
 /**
  * 
  *  任务卡片管理接口.
@@ -34,7 +36,7 @@ public void update(List userIds, String taskId, String clickedKey) throw
     data.put("task_id", taskId);
     data.put("clicked_key", clickedKey);
 
-    String url = this.mainService.getWxCpConfigStorage().getApiUrl(MESSAGE_UPDATE_TASKCARD);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(UPDATE_TASK_CARD);
     this.mainService.post(url, WxGsonBuilder.create().toJson(data));
   }
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceApacheHttpClientImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceApacheHttpClientImpl.java
index 04bc0a5f6e..14e75125af 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceApacheHttpClientImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceApacheHttpClientImpl.java
@@ -9,8 +9,8 @@
 import me.chanjar.weixin.common.util.http.HttpType;
 import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
 import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
-import me.chanjar.weixin.cp.api.WxCpTpService;
 import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
+import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
 import org.apache.http.Consts;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
@@ -52,7 +52,7 @@ public String getSuiteAccessToken(boolean forceRefresh) throws WxErrorException
 
     synchronized (this.globalSuiteAccessTokenRefreshLock) {
       try {
-        HttpPost httpPost = new HttpPost(configStorage.getApiUrl(WxCpTpService.GET_SUITE_TOKEN));
+        HttpPost httpPost = new HttpPost(configStorage.getApiUrl(WxCpApiPathConsts.Tp.GET_SUITE_TOKEN));
         if (this.httpProxy != null) {
           RequestConfig config = RequestConfig.custom()
             .setProxy(this.httpProxy).build();
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceImpl.java
index 538209b77a..f5582021e7 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpTpServiceImpl.java
@@ -1,12 +1,12 @@
-package me.chanjar.weixin.cp.api.impl;
-
-/**
- * 
- *  默认接口实现类,使用apache httpclient实现
- * Created by zhenjun cai.
- * 
- * - * @author Binary Wang - */ -public class WxCpTpServiceImpl extends WxCpTpServiceApacheHttpClientImpl { -} +package me.chanjar.weixin.cp.api.impl; + +/** + *
+ *  默认接口实现类,使用apache httpclient实现
+ * Created by zhenjun cai.
+ * 
+ * + * @author zhenjun cai + */ +public class WxCpTpServiceImpl extends WxCpTpServiceApacheHttpClientImpl { +} 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 c38a680125..268ae6bc8e 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,24 +1,23 @@ package me.chanjar.weixin.cp.api.impl; import com.google.common.collect.Maps; -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.*; import com.google.gson.reflect.TypeToken; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.error.WxErrorException; -import me.chanjar.weixin.cp.WxCpConsts; 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.constant.WxCpApiPathConsts; import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; import java.util.List; import java.util.Map; +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.User.*; + /** *
  *  Created by BinaryWang on 2017/6/24.
@@ -26,34 +25,31 @@
  *
  * @author Binary Wang
  */
+@RequiredArgsConstructor
 public class WxCpUserServiceImpl implements WxCpUserService {
   private final WxCpService mainService;
 
-  public WxCpUserServiceImpl(WxCpService mainService) {
-    this.mainService = mainService;
-  }
-
   @Override
   public void authenticate(String userId) throws WxErrorException {
-    this.mainService.get(this.mainService.getWxCpConfigStorage().getApiUrl(WxCpUserService.URL_AUTHENTICATE + userId), null);
+    this.mainService.get(this.mainService.getWxCpConfigStorage().getApiUrl(USER_AUTHENTICATE + userId), null);
   }
 
   @Override
   public void create(WxCpUser user) throws WxErrorException {
-    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpUserService.URL_USER_CREATE);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(USER_CREATE);
     this.mainService.post(url, user.toJson());
   }
 
   @Override
   public void update(WxCpUser user) throws WxErrorException {
-    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpUserService.URL_USER_UPDATE);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(USER_UPDATE);
     this.mainService.post(url, user.toJson());
   }
 
   @Override
   public void delete(String... userIds) throws WxErrorException {
     if (userIds.length == 1) {
-      String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpUserService.URL_USER_DELETE + userIds[0]);
+      String url = this.mainService.getWxCpConfigStorage().getApiUrl(USER_DELETE + userIds[0]);
       this.mainService.get(url, null);
       return;
     }
@@ -65,12 +61,12 @@ public void delete(String... userIds) throws WxErrorException {
     }
 
     jsonObject.add("useridlist", jsonArray);
-    this.mainService.post(WxCpUserService.URL_USER_BATCH_DELETE, jsonObject.toString());
+    this.mainService.post(USER_BATCH_DELETE, jsonObject.toString());
   }
 
   @Override
   public WxCpUser getById(String userid) throws WxErrorException {
-    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpUserService.URL_USER_GET + userid);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(USER_GET + userid);
     String responseContent = this.mainService.get(url, null);
     return WxCpUser.fromJson(responseContent);
   }
@@ -87,7 +83,7 @@ public List listByDepartment(Long departId, Boolean fetchChild, Intege
       params += "&status=0";
     }
 
-    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpUserService.URL_USER_LIST + departId);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(USER_LIST + departId);
     String responseContent = this.mainService.get(url, params);
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return WxCpGsonBuilder.create()
@@ -109,7 +105,7 @@ public List listSimpleByDepartment(Long departId, Boolean fetchChild,
       params += "&status=0";
     }
 
-    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpUserService.URL_USER_SIMPLE_LIST + departId);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(USER_SIMPLE_LIST + departId);
     String responseContent = this.mainService.get(url, params);
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return WxCpGsonBuilder.create()
@@ -147,13 +143,13 @@ public WxCpInviteResult invite(List userIds, List partyIds, List
       jsonObject.add("tag", jsonArray);
     }
 
-    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpUserService.URL_BATCH_INVITE);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(BATCH_INVITE);
     return WxCpInviteResult.fromJson(this.mainService.post(url, jsonObject.toString()));
   }
 
   @Override
   public Map userId2Openid(String userId, Integer agentId) throws WxErrorException {
-    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpUserService.URL_CONVERT_TO_OPENID);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(USER_CONVERT_TO_OPENID);
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("userid", userId);
     if (agentId != null) {
@@ -178,7 +174,7 @@ public Map userId2Openid(String userId, Integer agentId) throws
   public String openid2UserId(String openid) throws WxErrorException {
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("openid", openid);
-    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpUserService.URL_CONVERT_TO_USERID);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(USER_CONVERT_TO_USERID);
     String responseContent = this.mainService.post(url, jsonObject.toString());
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return tmpJsonElement.getAsJsonObject().get("userid").getAsString();
@@ -186,7 +182,7 @@ public String openid2UserId(String openid) throws WxErrorException {
 
   @Override
   public WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException {
-    String url = this.mainService.getWxCpConfigStorage().getApiUrl(WxCpUserService.URL_GET_EXTERNAL_CONTACT + userId);
+    String url = this.mainService.getWxCpConfigStorage().getApiUrl(GET_EXTERNAL_CONTACT + 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/WxCpAppChatMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAppChatMessage.java
index 96639f6c51..0af13a84dd 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAppChatMessage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAppChatMessage.java
@@ -6,7 +6,7 @@
 import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
-import me.chanjar.weixin.cp.WxCpConsts.AppChatMsgType;
+import me.chanjar.weixin.cp.constant.WxCpConsts.AppChatMsgType;
 import me.chanjar.weixin.cp.bean.article.MpnewsArticle;
 import me.chanjar.weixin.cp.bean.article.NewArticle;
 
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 e6b2be197a..72f63b5dda 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
@@ -162,7 +162,7 @@ public class WxCpXmlMessage implements Serializable {
 
   /**
    * 通讯录变更事件.
-   * 请参考常量 me.chanjar.weixin.cp.WxCpConsts.ContactChangeType
+   * 请参考常量 me.chanjar.weixin.cp.constant.WxCpConsts.ContactChangeType
    */
   @XStreamAlias("ChangeType")
   @XStreamConverter(value = XStreamCDataConverter.class)
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java
index a75ad1dfb1..c4dbf8f1a1 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java
@@ -6,7 +6,7 @@
 import java.io.File;
 
 /**
- * 微信客户端配置存储
+ * 微信客户端配置存储.
  *
  * @author Daniel Qian
  */
@@ -14,7 +14,6 @@ public interface WxCpConfigStorage {
 
   /**
    * 设置企业微信服务器 baseUrl.
-   *
    * 默认值是 https://qyapi.weixin.qq.com , 如果使用默认值,则不需要调用 setBaseApiUrl
    *
    * @param baseUrl 企业微信服务器 Url
@@ -23,7 +22,6 @@ public interface WxCpConfigStorage {
 
   /**
    * 读取企业微信 API Url.
-   *
    * 支持私有化企业微信服务器.
    */
   String getApiUrl(String path);
@@ -33,7 +31,7 @@ public interface WxCpConfigStorage {
   boolean isAccessTokenExpired();
 
   /**
-   * 强制将access token过期掉
+   * 强制将access token过期掉.
    */
   void expireAccessToken();
 
@@ -46,12 +44,12 @@ public interface WxCpConfigStorage {
   boolean isJsapiTicketExpired();
 
   /**
-   * 强制将jsapi ticket过期掉
+   * 强制将jsapi ticket过期掉.
    */
   void expireJsapiTicket();
 
   /**
-   * 应该是线程安全的
+   * 应该是线程安全的.
    */
   void updateJsapiTicket(String jsapiTicket, int expiresInSeconds);
 
@@ -60,12 +58,12 @@ public interface WxCpConfigStorage {
   boolean isAgentJsapiTicketExpired();
 
   /**
-   * 强制将jsapi ticket过期掉
+   * 强制将jsapi ticket过期掉.
    */
   void expireAgentJsapiTicket();
 
   /**
-   * 应该是线程安全的
+   * 应该是线程安全的.
    */
   void updateAgentJsapiTicket(String jsapiTicket, int expiresInSeconds);
 
@@ -94,7 +92,7 @@ public interface WxCpConfigStorage {
   File getTmpDirFile();
 
   /**
-   * http client builder
+   * http client builder.
    *
    * @return ApacheHttpClientBuilder
    */
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 31e2a211d5..2ce5750710 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
@@ -2,6 +2,7 @@
 
 import me.chanjar.weixin.common.bean.WxAccessToken;
 import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
+import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
 import java.io.File;
@@ -12,7 +13,6 @@
  * @author Daniel Qian
  */
 public class WxCpInMemoryConfigStorage implements WxCpConfigStorage {
-
   protected volatile String corpId;
   protected volatile String corpSecret;
 
@@ -49,7 +49,7 @@ public void setBaseApiUrl(String baseUrl) {
   @Override
   public String getApiUrl(String path) {
     if (baseApiUrl == null) {
-      baseApiUrl = "https://qyapi.weixin.qq.com";
+      baseApiUrl = WxCpApiPathConsts.DEFAULT_CP_BASE_URL;
     }
     return baseApiUrl + path;
   }
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 b8deef1d51..652f5fe0c6 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
@@ -2,6 +2,7 @@
 
 import me.chanjar.weixin.common.bean.WxAccessToken;
 import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
+import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
 import redis.clients.jedis.Jedis;
 import redis.clients.jedis.JedisPool;
 import redis.clients.jedis.JedisPoolConfig;
@@ -48,7 +49,7 @@ public void setBaseApiUrl(String baseUrl) {
   @Override
   public String getApiUrl(String path) {
     if (baseApiUrl == null) {
-      baseApiUrl = "https://qyapi.weixin.qq.com";
+      baseApiUrl = WxCpApiPathConsts.DEFAULT_CP_BASE_URL;
     }
     return baseApiUrl + path;
   }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
new file mode 100644
index 0000000000..9e1294db5c
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
@@ -0,0 +1,106 @@
+package me.chanjar.weixin.cp.constant;
+
+
+/**
+ * 
+ *  企业微信api地址常量类
+ *  Created by BinaryWang on 2019-06-02.
+ * 
+ * + * @author Binary Wang + */ +public final class WxCpApiPathConsts { + public static final String DEFAULT_CP_BASE_URL = "https://qyapi.weixin.qq.com"; + + public static final String GET_JSAPI_TICKET = "/cgi-bin/get_jsapi_ticket"; + public static final String GET_AGENT_CONFIG_TICKET = "/cgi-bin/ticket/get?&type=agent_config"; + public static final String MESSAGE_SEND = "/cgi-bin/message/send"; + public static final String GET_CALLBACK_IP = "/cgi-bin/getcallbackip"; + public static final String BATCH_REPLACE_PARTY = "/cgi-bin/batch/replaceparty"; + public static final String BATCH_REPLACE_USER = "/cgi-bin/batch/replaceuser"; + public static final String BATCH_GET_RESULT = "/cgi-bin/batch/getresult?jobid="; + public static final String JSCODE_TO_SESSION = "/cgi-bin/miniprogram/jscode2session"; + public static final String GET_TOKEN = "/cgi-bin/gettoken?&corpid=%s&corpsecret=%s"; + + public static class Agent { + public static final String AGENT_GET = "/cgi-bin/agent/get?agentid=%d"; + public static final String AGENT_SET = "/cgi-bin/agent/set"; + public static final String AGENT_LIST = "/cgi-bin/agent/list"; + } + + public static class OAuth2 { + public static final String GET_USER_INFO = "/cgi-bin/user/getuserinfo?code=%s&agentid=%d"; + public static final String GET_USER_DETAIL = "/cgi-bin/user/getuserdetail"; + public static final String URL_OAUTH2_AUTHORIZE = "https://open.weixin.qq.com/connect/oauth2/authorize"; + } + + public static class Chat { + public static final String APPCHAT_CREATE = "/cgi-bin/appchat/create"; + public static final String APPCHAT_UPDATE = "/cgi-bin/appchat/update"; + public static final String APPCHAT_GET_CHATID = "/cgi-bin/appchat/get?chatid="; + public static final String APPCHAT_SEND = "/cgi-bin/appchat/send"; + } + + public static class Department { + public static final String DEPARTMENT_CREATE = "/cgi-bin/department/create"; + public static final String DEPARTMENT_UPDATE = "/cgi-bin/department/update"; + public static final String DEPARTMENT_DELETE = "/cgi-bin/department/delete?id=%d"; + public static final String DEPARTMENT_LIST = "/cgi-bin/department/list"; + } + + public static class Media { + public static final String MEDIA_GET = "/cgi-bin/media/get"; + public static final String MEDIA_UPLOAD = "/cgi-bin/media/upload?type="; + public static final String IMG_UPLOAD = "/cgi-bin/media/uploadimg"; + public static final String JSSDK_MEDIA_GET = "/cgi-bin/media/get/jssdk"; + } + + public static class Menu { + public static final String MENU_CREATE = "/cgi-bin/menu/create?agentid=%d"; + public static final String MENU_DELETE = "/cgi-bin/menu/delete?agentid=%d"; + public static final String MENU_GET = "/cgi-bin/menu/get?agentid=%d"; + } + + public static class Oa { + public static final String GET_CHECKIN_DATA = "/cgi-bin/checkin/getcheckindata"; + public static final String GET_CHECKIN_OPTION = "/cgi-bin/checkin/getcheckinoption"; + public static final String GET_APPROVAL_DATA = "/cgi-bin/corp/getapprovaldata"; + public static final String GET_DIAL_RECORD = "/cgi-bin/dial/get_dial_record"; + } + + public static class Tag { + public static final String TAG_CREATE = "/cgi-bin/tag/create"; + public static final String TAG_UPDATE = "/cgi-bin/tag/update"; + public static final String TAG_DELETE = "/cgi-bin/tag/delete?tagid=%s"; + public static final String TAG_LIST = "/cgi-bin/tag/list"; + public static final String TAG_GET = "/cgi-bin/tag/get?tagid=%s"; + public static final String TAG_ADD_TAG_USERS = "/cgi-bin/tag/addtagusers"; + public static final String TAG_DEL_TAG_USERS = "/cgi-bin/tag/deltagusers"; + } + + public static class TaskCard { + public static final String UPDATE_TASK_CARD = "/cgi-bin/message/update_taskcard"; + } + + public static class Tp { + public static final String JSCODE_TO_SESSION = "/cgi-bin/service/miniprogram/jscode2session"; + public static final String GET_CORP_TOKEN = "/cgi-bin/service/get_corp_token"; + public static final String GET_PERMANENT_CODE = "/cgi-bin/service/get_permanent_code"; + public static final String GET_SUITE_TOKEN = "/cgi-bin/service/get_suite_token"; + } + + public static class User { + public static final String USER_AUTHENTICATE = "/cgi-bin/user/authsucc?userid="; + public static final String USER_CREATE = "/cgi-bin/user/create"; + public static final String USER_UPDATE = "/cgi-bin/user/update"; + public static final String USER_DELETE = "/cgi-bin/user/delete?userid="; + public static final String USER_BATCH_DELETE = "/cgi-bin/user/batchdelete"; + public static final String USER_GET = "/cgi-bin/user/get?userid="; + public static final String USER_LIST = "/cgi-bin/user/list?department_id="; + public static final String USER_SIMPLE_LIST = "/cgi-bin/user/simplelist?department_id="; + public static final String BATCH_INVITE = "/cgi-bin/batch/invite"; + public static final String USER_CONVERT_TO_OPENID = "/cgi-bin/user/convert_to_openid"; + public static final String USER_CONVERT_TO_USERID = "/cgi-bin/user/convert_to_userid"; + public static final String GET_EXTERNAL_CONTACT = "/cgi-bin/crm/get_external_contact?external_userid="; + } +} 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/constant/WxCpConsts.java similarity index 99% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/WxCpConsts.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java index 87892eccdd..b3809ad0c3 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/WxCpConsts.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.cp; +package me.chanjar.weixin.cp.constant; /** *
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 9fabe55068..50aa98dca9 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
@@ -2,11 +2,11 @@
 
 import com.google.inject.Inject;
 import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.cp.WxCpConsts;
 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.constant.WxCpApiPathConsts;
 import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
@@ -70,7 +70,7 @@ public static class MockTest {
     @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(String.format(wxService.getWxCpConfigStorage().getApiUrl(WxCpAgentService.GET_AGENT), 9), null)).thenReturn(returnJson);
+      when(wxService.get(String.format(wxService.getWxCpConfigStorage().getApiUrl(WxCpApiPathConsts.Agent.AGENT_GET), 9), null)).thenReturn(returnJson);
       when(wxService.getAgentService()).thenReturn(new WxCpAgentServiceImpl(wxService));
 
       WxCpAgentService wxAgentService = this.wxService.getAgentService();
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImplTest.java
index 4b25985f11..bb4d3904d0 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpChatServiceImplTest.java
@@ -8,7 +8,7 @@
 import com.google.common.collect.Lists;
 import com.google.inject.Inject;
 import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.cp.WxCpConsts.AppChatMsgType;
+import me.chanjar.weixin.cp.constant.WxCpConsts.AppChatMsgType;
 import me.chanjar.weixin.cp.api.ApiTestModule;
 import me.chanjar.weixin.cp.api.WxCpService;
 import me.chanjar.weixin.cp.bean.WxCpAppChatMessage;
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java
index 858fde203c..ac90114071 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java
@@ -10,6 +10,7 @@
 import me.chanjar.weixin.cp.bean.WxCpTagAddOrRemoveUsersResult;
 import me.chanjar.weixin.cp.bean.WxCpTagGetResult;
 import me.chanjar.weixin.cp.bean.WxCpUser;
+import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
 import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
@@ -82,7 +83,7 @@ public void testDelete() throws Exception {
   public void testGet() throws WxErrorException {
     String apiResultJson = "{\"errcode\": 0,\"errmsg\": \"ok\",\"userlist\": [{\"userid\": \"0124035\",\"name\": \"王五\"},{\"userid\": \"0114035\",\"name\": \"梦雪\"}],\"partylist\": [9576,9567,9566],\"tagname\": \"测试标签-001\"}";
     WxCpService wxService = mock(WxCpService.class);
-    when(wxService.get(String.format(wxService.getWxCpConfigStorage().getApiUrl(WxCpTagService.TAG_GET), 150), null)).thenReturn(apiResultJson);
+    when(wxService.get(String.format(wxService.getWxCpConfigStorage().getApiUrl(WxCpApiPathConsts.Tag.TAG_GET), 150), null)).thenReturn(apiResultJson);
     when(wxService.getTagService()).thenReturn(new WxCpTagServiceImpl(wxService));
 
     WxCpTagService wxCpTagService = wxService.getTagService();
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java
index 89c0396e08..11a2dbe469 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java
@@ -3,7 +3,7 @@
 import me.chanjar.weixin.common.api.WxConsts;
 import org.testng.annotations.Test;
 
-import static me.chanjar.weixin.cp.WxCpConsts.EventType.TASKCARD_CLICK;
+import static me.chanjar.weixin.cp.constant.WxCpConsts.EventType.TASKCARD_CLICK;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
 
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 ff204a80f0..df656a68a8 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
@@ -10,7 +10,7 @@
 
 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.constant.WxCpConsts;
 import me.chanjar.weixin.cp.api.WxCpService;
 import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
 import me.chanjar.weixin.cp.bean.WxCpXmlMessage;

From 14bc2f5dc76aa0beacbf113a35c47373ef7a9e8d Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sun, 2 Jun 2019 15:37:10 +0800
Subject: [PATCH 12/74] fix test code

---
 pom.xml                                                      | 1 +
 .../java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java     | 5 +++--
 .../chanjar/weixin/cp/api/impl/WxCpAgentServiceImplTest.java | 1 +
 .../chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java   | 1 +
 4 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index 07631b61b7..743903fe45 100644
--- a/pom.xml
+++ b/pom.xml
@@ -370,6 +370,7 @@
         maven-checkstyle-plugin
         2.17
         
+          true
           quality-checks/google_checks.xml
           true
           true
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java
index 2e89e5e79d..0bd8a24de3 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java
@@ -1,5 +1,6 @@
 package me.chanjar.weixin.cp.api;
 
+import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
@@ -13,8 +14,8 @@
 import java.util.concurrent.Future;
 
 @Test
+@Slf4j
 public class WxCpBusyRetryTest {
-
   @DataProvider(name = "getService")
   public Object[][] getService() {
     WxCpService service = new WxCpServiceImpl() {
@@ -23,7 +24,7 @@ public Object[][] getService() {
       public synchronized  T executeInternal(
         RequestExecutor executor, String uri, E data)
         throws WxErrorException {
-        this.log.info("Executed");
+        log.info("Executed");
         throw new WxErrorException(WxError.builder().errorCode(-1).build());
       }
     };
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 50aa98dca9..90d2f14a44 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
@@ -15,6 +15,7 @@
 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;
 
 
 /**
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java
index ac90114071..8d21bf17f7 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpTagServiceImplTest.java
@@ -18,6 +18,7 @@
 
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotEquals;
 
 /**

From 614165d66a799d58054f31b0d7c820dc75f40668 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sun, 2 Jun 2019 15:54:58 +0800
Subject: [PATCH 13/74] Update .travis.yml

---
 .travis.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index 60c4d53e7c..6910a67e18 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,7 +8,7 @@ language: java
 
 jdk:
   - oraclejdk8
-script: "./mvnw clean package -DskipTests=true -Dcheckstyle.skip=true"
+script: "mvn clean package -DskipTests=true -Dcheckstyle.skip=true"
 
 #script:
 #  - mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar

From 14bc77c753af1c9e683f601c187f58e6e9dea34a Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sun, 2 Jun 2019 16:44:15 +0800
Subject: [PATCH 14/74] =?UTF-8?q?=E5=8F=91=E5=B8=833.4.2.B=E6=B5=8B?=
 =?UTF-8?q?=E8=AF=95=E7=89=88=E6=9C=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pom.xml                              | 2 +-
 starters/wx-java-mp-starter/pom.xml  | 2 +-
 starters/wx-java-pay-starter/pom.xml | 2 +-
 weixin-java-common/pom.xml           | 2 +-
 weixin-java-cp/pom.xml               | 2 +-
 weixin-java-miniapp/pom.xml          | 2 +-
 weixin-java-mp/pom.xml               | 2 +-
 weixin-java-open/pom.xml             | 2 +-
 weixin-java-pay/pom.xml              | 2 +-
 9 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/pom.xml b/pom.xml
index 743903fe45..8f74380695 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
   4.0.0
   com.github.binarywang
   wx-java
-  3.4.1.B
+  3.4.2.B
   pom
   WxJava - Weixin/Wechat Java SDK
   微信开发Java SDK
diff --git a/starters/wx-java-mp-starter/pom.xml b/starters/wx-java-mp-starter/pom.xml
index 2c276e94e2..1edd7350ea 100644
--- a/starters/wx-java-mp-starter/pom.xml
+++ b/starters/wx-java-mp-starter/pom.xml
@@ -6,7 +6,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.1.B
+    3.4.2.B
     ../../
   
 
diff --git a/starters/wx-java-pay-starter/pom.xml b/starters/wx-java-pay-starter/pom.xml
index 4201da5b76..0f9fce58ac 100644
--- a/starters/wx-java-pay-starter/pom.xml
+++ b/starters/wx-java-pay-starter/pom.xml
@@ -5,7 +5,7 @@
   
     wx-java
     com.github.binarywang
-    3.4.1.B
+    3.4.2.B
     ../../
   
   4.0.0
diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml
index 2ddba54d34..539d61ef28 100644
--- a/weixin-java-common/pom.xml
+++ b/weixin-java-common/pom.xml
@@ -6,7 +6,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.1.B
+    3.4.2.B
   
 
   weixin-java-common
diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml
index 8de47acac2..22624b9b92 100644
--- a/weixin-java-cp/pom.xml
+++ b/weixin-java-cp/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.1.B
+    3.4.2.B
   
 
   weixin-java-cp
diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml
index 3c7b511468..3f7f662acb 100644
--- a/weixin-java-miniapp/pom.xml
+++ b/weixin-java-miniapp/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.1.B
+    3.4.2.B
   
 
   weixin-java-miniapp
diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml
index 8bd9841711..698859868f 100644
--- a/weixin-java-mp/pom.xml
+++ b/weixin-java-mp/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.1.B
+    3.4.2.B
   
 
   weixin-java-mp
diff --git a/weixin-java-open/pom.xml b/weixin-java-open/pom.xml
index 549aa5b4fa..10364fba7c 100644
--- a/weixin-java-open/pom.xml
+++ b/weixin-java-open/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.1.B
+    3.4.2.B
   
 
   weixin-java-open
diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml
index 115b07e286..4fd46c21d9 100644
--- a/weixin-java-pay/pom.xml
+++ b/weixin-java-pay/pom.xml
@@ -5,7 +5,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.1.B
+    3.4.2.B
   
   4.0.0
 

From e937d3f5f5aad2450ccd75ac5f16cf0469603a85 Mon Sep 17 00:00:00 2001
From: Jink2005 
Date: Thu, 6 Jun 2019 11:39:25 +0800
Subject: [PATCH 15/74] =?UTF-8?q?#1067=20=E5=BE=AE=E4=BF=A1=E6=94=AF?=
 =?UTF-8?q?=E4=BB=98=E7=BB=9F=E4=B8=80=E4=B8=8B=E5=8D=95=E8=87=AA=E5=AE=9A?=
 =?UTF-8?q?=E4=B9=89=E7=BB=93=E6=9E=9C=E5=B0=81=E8=A3=85=E7=B1=BB=E5=AE=9E?=
 =?UTF-8?q?=E7=8E=B0=E5=BA=8F=E5=88=97=E5=8C=96=E6=8E=A5=E5=8F=A3=EF=BC=8C?=
 =?UTF-8?q?=E4=BB=A5=E6=BB=A1=E8=B6=B3=E6=9F=90=E4=BA=9B=E5=BA=94=E7=94=A8?=
 =?UTF-8?q?=E5=9C=BA=E6=99=AF=E9=9C=80=E6=B1=82=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../binarywang/wxpay/bean/order/WxPayAppOrderResult.java     | 4 +++-
 .../binarywang/wxpay/bean/order/WxPayMpOrderResult.java      | 4 +++-
 .../binarywang/wxpay/bean/order/WxPayMwebOrderResult.java    | 5 +++--
 .../binarywang/wxpay/bean/order/WxPayNativeOrderResult.java  | 5 +++--
 4 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayAppOrderResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayAppOrderResult.java
index 164c30b3c5..2ff290056f 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayAppOrderResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayAppOrderResult.java
@@ -3,6 +3,8 @@
 import lombok.Builder;
 import lombok.Data;
 
+import java.io.Serializable;
+
 /**
  * 
  * APP支付调用统一下单接口后的组装所需参数的实现类
@@ -14,7 +16,7 @@
  */
 @Data
 @Builder
-public class WxPayAppOrderResult {
+public class WxPayAppOrderResult implements Serializable {
   private String sign;
   private String prepayId;
   private String partnerId;
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMpOrderResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMpOrderResult.java
index 04cf893feb..ad6d27b507 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMpOrderResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMpOrderResult.java
@@ -4,6 +4,8 @@
 import lombok.Builder;
 import lombok.Data;
 
+import java.io.Serializable;
+
 /**
  * 
  * 微信公众号支付进行统一下单后组装所需参数的类
@@ -15,7 +17,7 @@
  */
 @Data
 @Builder
-public class WxPayMpOrderResult {
+public class WxPayMpOrderResult implements Serializable {
   private String appId;
   private String timeStamp;
   private String nonceStr;
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMwebOrderResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMwebOrderResult.java
index 640d3cd3de..a2240f5dac 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMwebOrderResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMwebOrderResult.java
@@ -2,9 +2,10 @@
 
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import lombok.AllArgsConstructor;
-import lombok.Builder;
 import lombok.Data;
 
+import java.io.Serializable;
+
 /**
  * 
  * 微信H5支付统一下单后发起支付拼接所需参数实现类.
@@ -15,7 +16,7 @@
  */
 @Data
 @AllArgsConstructor
-public class WxPayMwebOrderResult {
+public class WxPayMwebOrderResult implements Serializable {
   @XStreamAlias("mwebUrl")
   private String mwebUrl;
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayNativeOrderResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayNativeOrderResult.java
index 219c47a6f9..4a371c1fca 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayNativeOrderResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayNativeOrderResult.java
@@ -1,9 +1,10 @@
 package com.github.binarywang.wxpay.bean.order;
 
 import lombok.AllArgsConstructor;
-import lombok.Builder;
 import lombok.Data;
 
+import java.io.Serializable;
+
 /**
  * 
  * 微信扫码支付统一下单后发起支付拼接所需参数实现类
@@ -14,6 +15,6 @@
  */
 @Data
 @AllArgsConstructor
-public class WxPayNativeOrderResult {
+public class WxPayNativeOrderResult implements Serializable {
   private String codeUrl;
 }

From 1ac042695dafc101f2ada1522fb6dcb1ad5aa869 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Thu, 6 Jun 2019 14:02:16 +0800
Subject: [PATCH 16/74] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=87=8D=E6=9E=84?=
 =?UTF-8?q?=E4=BB=A3=E7=A0=81=EF=BC=8C=E7=BB=9F=E4=B8=80=E7=AE=A1=E7=90=86?=
 =?UTF-8?q?=E5=85=AC=E4=BC=97=E5=8F=B7=E6=8E=A5=E5=8F=A3=E5=9C=B0=E5=9D=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../weixin/mp/api/WxMpAiOpenService.java      |   3 -
 .../weixin/mp/api/WxMpCardService.java        |  21 -
 .../weixin/mp/api/WxMpConfigStorage.java      |   1 -
 .../weixin/mp/api/WxMpDataCubeService.java    |  18 -
 .../weixin/mp/api/WxMpDeviceService.java      |   2 +
 .../weixin/mp/api/WxMpKefuService.java        |  16 -
 .../weixin/mp/api/WxMpMarketingService.java   |   2 -
 .../weixin/mp/api/WxMpMassMessageService.java |  28 +-
 .../weixin/mp/api/WxMpMaterialService.java    |  13 +-
 .../weixin/mp/api/WxMpMemberCardService.java  |  25 -
 .../weixin/mp/api/WxMpMenuService.java        |   3 +-
 .../weixin/mp/api/WxMpQrcodeService.java      |   1 -
 .../me/chanjar/weixin/mp/api/WxMpService.java | 121 +--
 .../weixin/mp/api/WxMpShakeService.java       |   3 +-
 .../weixin/mp/api/WxMpStoreService.java       |  10 +-
 .../mp/api/WxMpSubscribeMsgService.java       |   1 -
 .../weixin/mp/api/WxMpTemplateMsgService.java |   1 -
 .../weixin/mp/api/WxMpUserService.java        |  17 +-
 .../weixin/mp/api/WxMpUserTagService.java     |   1 -
 .../mp/api/impl/BaseWxMpServiceImpl.java      |  63 +-
 .../mp/api/impl/WxMpAiOpenServiceImpl.java    |  19 +-
 .../mp/api/impl/WxMpCardServiceImpl.java      |  25 +-
 .../mp/api/impl/WxMpDataCubeServiceImpl.java  |  20 +-
 .../mp/api/impl/WxMpDeviceServiceImpl.java    |  48 +-
 .../mp/api/impl/WxMpKefuServiceImpl.java      |  39 +-
 .../mp/api/impl/WxMpMarketingServiceImpl.java |  28 +-
 .../api/impl/WxMpMassMessageServiceImpl.java  |  26 +-
 .../mp/api/impl/WxMpMaterialServiceImpl.java  |  64 +-
 .../api/impl/WxMpMemberCardServiceImpl.java   |  33 +-
 .../mp/api/impl/WxMpMenuServiceImpl.java      |  43 +-
 .../mp/api/impl/WxMpQrcodeServiceImpl.java    |  95 +-
 .../api/impl/WxMpServiceHttpClientImpl.java   |   8 +-
 .../mp/api/impl/WxMpServiceJoddHttpImpl.java  |   9 +-
 .../mp/api/impl/WxMpServiceOkHttpImpl.java    |  10 +-
 .../mp/api/impl/WxMpShakeServiceImpl.java     |  45 +-
 .../mp/api/impl/WxMpStoreServiceImpl.java     |  21 +-
 .../api/impl/WxMpSubscribeMsgServiceImpl.java |  20 +-
 .../api/impl/WxMpTemplateMsgServiceImpl.java  |  30 +-
 .../impl/WxMpUserBlacklistServiceImpl.java    |  33 +-
 .../mp/api/impl/WxMpUserServiceImpl.java      |  28 +-
 .../mp/api/impl/WxMpUserTagServiceImpl.java   |  52 +-
 .../mp/api/impl/WxMpWifiServiceImpl.java      |  13 +-
 .../me/chanjar/weixin/mp/bean/card/Card.java  |   3 +-
 .../chanjar/weixin/mp/enums/WxMpApiUrl.java   | 837 ++++++++++++++++++
 .../weixin/mp/api/WxMpBusyRetryTest.java      |   8 +-
 .../chanjar/weixin/mp/api/WxMpJsAPITest.java  |  10 +-
 .../mp/api/impl/WxMpUserServiceImplTest.java  |  33 +-
 47 files changed, 1288 insertions(+), 662 deletions(-)
 create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java

diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpAiOpenService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpAiOpenService.java
index c57ad9d0f5..230910e888 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpAiOpenService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpAiOpenService.java
@@ -15,9 +15,6 @@
  * @author Binary Wang
  */
 public interface WxMpAiOpenService {
-  String TRANSLATE_URL = "http://api.weixin.qq.com/cgi-bin/media/voice/translatecontent?lfrom=%s<o=%s";
-  String VOICE_UPLOAD_URL = "http://api.weixin.qq.com/cgi-bin/media/voice/addvoicetorecofortext?format=%s&voice_id=%s&lang=%s";
-  String VOICE_QUERY_RESULT_URL = "http://api.weixin.qq.com/cgi-bin/media/voice/queryrecoresultfortext";
 
   /**
    * 
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 e7f2db4f87..8b9a599448 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
@@ -11,27 +11,6 @@
  * @author yuanqixun 2018-08-29
  */
 public interface WxMpCardService {
-  String CARD_CREATE = "https://api.weixin.qq.com/card/create";
-  String CARD_GET = "https://api.weixin.qq.com/card/get";
-  String CARD_GET_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card";
-  String CARD_CODE_DECRYPT = "https://api.weixin.qq.com/card/code/decrypt";
-  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_CREATE = "https://api.weixin.qq.com/card/qrcode/create";
-  String CARD_LANDING_PAGE_CREATE = "https://api.weixin.qq.com/card/landingpage/create";
-
-  /**
-   * 将用户的卡券设置为失效状态.
-   */
-  String CARD_CODE_UNAVAILABLE = "https://api.weixin.qq.com/card/code/unavailable";
-
-  /**
-   * 卡券删除.
-   */
-  String CARD_DELETE = "https://api.weixin.qq.com/card/delete";
-
   /**
    * 得到WxMpService.
    */
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java
index d51ea88b8e..53e5fc6943 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java
@@ -13,7 +13,6 @@
  * @author chanjarster
  */
 public interface WxMpConfigStorage {
-
   String getAccessToken();
 
   Lock getAccessTokenLock();
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDataCubeService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDataCubeService.java
index fecceea444..c1b35bee5f 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDataCubeService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDataCubeService.java
@@ -13,24 +13,6 @@
  * @author binarywang (https://github.com/binarywang)
  */
 public interface WxMpDataCubeService {
-  String GET_USER_SUMMARY = "https://api.weixin.qq.com/datacube/getusersummary";
-  String GET_USER_CUMULATE = "https://api.weixin.qq.com/datacube/getusercumulate";
-  String GET_ARTICLE_SUMMARY = "https://api.weixin.qq.com/datacube/getarticlesummary";
-  String GET_ARTICLE_TOTAL = "https://api.weixin.qq.com/datacube/getarticletotal";
-  String GET_USER_READ = "https://api.weixin.qq.com/datacube/getuserread";
-  String GET_USER_READ_HOUR = "https://api.weixin.qq.com/datacube/getuserreadhour";
-  String GET_USER_SHARE = "https://api.weixin.qq.com/datacube/getusershare";
-  String GET_USER_SHARE_HOUR = "https://api.weixin.qq.com/datacube/getusersharehour";
-  String GET_UPSTREAM_MSG = "https://api.weixin.qq.com/datacube/getupstreammsg";
-  String GET_UPSTREAM_MSG_HOUR = "https://api.weixin.qq.com/datacube/getupstreammsghour";
-  String GET_UPSTREAM_MSG_WEEK = "https://api.weixin.qq.com/datacube/getupstreammsgweek";
-  String GET_UPSTREAM_MSG_MONTH = "https://api.weixin.qq.com/datacube/getupstreammsgmonth";
-  String GET_UPSTREAM_MSG_DIST = "https://api.weixin.qq.com/datacube/getupstreammsgdist";
-  String GET_UPSTREAM_MSG_DIST_WEEK = "https://api.weixin.qq.com/datacube/getupstreammsgdistweek";
-  String GET_UPSTREAM_MSG_DIST_MONTH = "https://api.weixin.qq.com/datacube/getupstreammsgdistmonth";
-  String GET_INTERFACE_SUMMARY = "https://api.weixin.qq.com/datacube/getinterfacesummary";
-  String GET_INTERFACE_SUMMARY_HOUR = "https://api.weixin.qq.com/datacube/getinterfacesummaryhour";
-
   //*******************用户分析数据接口***********************//
 
   /**
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDeviceService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDeviceService.java
index 8a0fb6a58e..c2ccef5a64 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDeviceService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpDeviceService.java
@@ -5,6 +5,8 @@
 
 /**
  * Created by keungtung on 10/12/2016.
+ *
+ * @author keungtung
  */
 public interface WxMpDeviceService {
   /**
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 99dcaba99b..3404f5fe2e 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
@@ -22,22 +22,6 @@
  * @author Binary Wang
  */
 public interface WxMpKefuService {
-  String MESSAGE_CUSTOM_SEND = "https://api.weixin.qq.com/cgi-bin/message/custom/send";
-  String GET_KF_LIST = "https://api.weixin.qq.com/cgi-bin/customservice/getkflist";
-  String GET_ONLINE_KF_LIST = "https://api.weixin.qq.com/cgi-bin/customservice/getonlinekflist";
-  String KFACCOUNT_ADD = "https://api.weixin.qq.com/customservice/kfaccount/add";
-  String KFACCOUNT_UPDATE = "https://api.weixin.qq.com/customservice/kfaccount/update";
-  String KFACCOUNT_INVITE_WORKER = "https://api.weixin.qq.com/customservice/kfaccount/inviteworker";
-  String KFACCOUNT_UPLOAD_HEAD_IMG = "https://api.weixin.qq.com/customservice/kfaccount/uploadheadimg?kf_account=%s";
-  String KFACCOUNT_DEL = "https://api.weixin.qq.com/customservice/kfaccount/del?kf_account=%s";
-  String KFSESSION_CREATE = "https://api.weixin.qq.com/customservice/kfsession/create";
-  String KFSESSION_CLOSE = "https://api.weixin.qq.com/customservice/kfsession/close";
-  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 MSG_RECORD_LIST = "https://api.weixin.qq.com/customservice/msgrecord/getmsglist";
-  String CUSTOM_TYPING = "https://api.weixin.qq.com/cgi-bin/message/custom/typing";
-
   /**
    * 
    * 发送客服消息
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMarketingService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMarketingService.java
index f59158b2bd..c35a135ce7 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMarketingService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMarketingService.java
@@ -18,8 +18,6 @@
  * @author 007
  */
 public interface WxMpMarketingService {
-  String API_URL_PREFIX = "https://api.weixin.qq.com/marketing/";
-
   /**
    * 
    * 创建数据源
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMassMessageService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMassMessageService.java
index f3e8db9d10..c986e53e34 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMassMessageService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMassMessageService.java
@@ -14,31 +14,6 @@
  * @author Binary Wang
  */
 public interface WxMpMassMessageService {
-  /**
-   * 上传群发用的图文消息.
-   */
-  String MEDIA_UPLOAD_NEWS_URL = "https://api.weixin.qq.com/cgi-bin/media/uploadnews";
-  /**
-   * 上传群发用的视频.
-   */
-  String MEDIA_UPLOAD_VIDEO_URL = "https://api.weixin.qq.com/cgi-bin/media/uploadvideo";
-  /**
-   * 分组群发消息.
-   */
-  String MESSAGE_MASS_SENDALL_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall";
-  /**
-   * 按openId列表群发消息.
-   */
-  String MESSAGE_MASS_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/send";
-  /**
-   * 群发消息预览接口.
-   */
-  String MESSAGE_MASS_PREVIEW_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/preview";
-  /**
-   * 删除群发接口.
-   */
-  String MESSAGE_MASS_DELETE_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/delete";
-
   /**
    * 
    * 上传群发用的图文消息,上传后才能群发图文消息.
@@ -85,7 +60,8 @@ public interface WxMpMassMessageService {
   /**
    * 
    * 群发消息预览接口.
-   * 开发者可通过该接口发送消息给指定用户,在手机端查看消息的样式和排版。为了满足第三方平台开发者的需求,在保留对openID预览能力的同时,增加了对指定微信号发送预览的能力,但该能力每日调用次数有限制(100次),请勿滥用。
+   * 开发者可通过该接口发送消息给指定用户,在手机端查看消息的样式和排版。为了满足第三方平台开发者的需求,
+   * 在保留对openID预览能力的同时,增加了对指定微信号发送预览的能力,但该能力每日调用次数有限制(100次),请勿滥用。
    * 接口调用请求说明
    *  http请求方式: POST
    *  https://api.weixin.qq.com/cgi-bin/message/mass/preview?access_token=ACCESS_TOKEN
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 6d762f1c44..686c86f20d 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
@@ -22,19 +22,10 @@
  * 即以https://api.weixin.qq.com/cgi-bin/material
  * 和 https://api.weixin.qq.com/cgi-bin/media开头的接口
  * 
+ * + * @author Binary Wang */ public interface WxMpMaterialService { - String MEDIA_GET_URL = "https://api.weixin.qq.com/cgi-bin/media/get"; - String MEDIA_UPLOAD_URL = "https://api.weixin.qq.com/cgi-bin/media/upload?type=%s"; - String IMG_UPLOAD_URL = "https://api.weixin.qq.com/cgi-bin/media/uploadimg"; - String MATERIAL_ADD_URL = "https://api.weixin.qq.com/cgi-bin/material/add_material?type=%s"; - String NEWS_ADD_URL = "https://api.weixin.qq.com/cgi-bin/material/add_news"; - String MATERIAL_GET_URL = "https://api.weixin.qq.com/cgi-bin/material/get_material"; - String NEWS_UPDATE_URL = "https://api.weixin.qq.com/cgi-bin/material/update_news"; - String MATERIAL_DEL_URL = "https://api.weixin.qq.com/cgi-bin/material/del_material"; - String MATERIAL_GET_COUNT_URL = "https://api.weixin.qq.com/cgi-bin/material/get_materialcount"; - String MATERIAL_BATCHGET_URL = "https://api.weixin.qq.com/cgi-bin/material/batchget_material"; - /** *
    * 新增临时素材
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 37785365c1..e551f7d989 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
@@ -17,31 +17,6 @@
  * @date 2018-08-30
  */
 public interface WxMpMemberCardService {
-  String MEMBER_CARD_CREATE = "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_ACTIVATE_USER_FORM = "https://api.weixin.qq.com/card/membercard/activateuserform/set";
-
-  /**
-   * 获取会员卡开卡插件参数.
-   */
-  String MEMBER_CARD_ACTIVATE_URL = "https://api.weixin.qq.com/card/membercard/activate/geturl";
-
-  /**
-   * 会员卡信息更新.
-   */
-  String MEMBER_CARD_UPDATE = "https://api.weixin.qq.com/card/update";
-
-  /**
-   * 跳转型会员卡开卡字段.
-   * 获取用户提交资料(wx_activate=true情况调用),开发者根据activate_ticket获取到用户填写的信息
-   */
-  String MEMBER_CARD_ACTIVATE_TEMP_INFO = "https://api.weixin.qq.com/card/membercard/activatetempinfo/get";
-
   /**
    * 得到WxMpService.
    *
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java
index f0fe549575..e7cef4ebb3 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java
@@ -6,12 +6,11 @@
 import me.chanjar.weixin.mp.bean.menu.WxMpMenu;
 
 /**
- * 菜单相关操作接口
+ * 菜单相关操作接口.
  *
  * @author Binary Wang
  */
 public interface WxMpMenuService {
-
   /**
    * 
    * 自定义菜单创建接口
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java
index 131ebf6341..6622159d22 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java
@@ -14,7 +14,6 @@
  * @author Binary Wang
  */
 public interface WxMpQrcodeService {
-
   /**
    * 
    * 换取临时二维码ticket
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
index a0452ebad7..92d17dbb7e 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
@@ -5,13 +5,13 @@
 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.mp.api.impl.BaseWxMpServiceImpl;
 import me.chanjar.weixin.mp.bean.WxMpSemanticQuery;
 import me.chanjar.weixin.mp.bean.result.WxMpCurrentAutoReplyInfo;
 import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
 import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult;
 import me.chanjar.weixin.mp.bean.result.WxMpUser;
 import me.chanjar.weixin.mp.enums.TicketType;
+import me.chanjar.weixin.mp.enums.WxMpApiUrl;
 
 import java.util.Map;
 
@@ -21,61 +21,6 @@
  * @author chanjarster
  */
 public interface WxMpService {
-  /**
-   * 获取access_token.
-   */
-  String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
-  /**
-   * 获得各种类型的ticket.
-   */
-  String GET_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=";
-  /**
-   * 长链接转短链接接口.
-   */
-  String SHORTURL_API_URL = "https://api.weixin.qq.com/cgi-bin/shorturl";
-  /**
-   * 语义查询接口.
-   */
-  String SEMANTIC_SEMPROXY_SEARCH_URL = "https://api.weixin.qq.com/semantic/semproxy/search";
-  /**
-   * 用code换取oauth2的access token.
-   */
-  String OAUTH2_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
-  /**
-   * 刷新oauth2的access token.
-   */
-  String OAUTH2_REFRESH_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s";
-  /**
-   * 用oauth2获取用户信息.
-   */
-  String OAUTH2_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=%s";
-  /**
-   * 验证oauth2的access token是否有效.
-   */
-  String OAUTH2_VALIDATE_TOKEN_URL = "https://api.weixin.qq.com/sns/auth?access_token=%s&openid=%s";
-  /**
-   * 获取微信服务器IP地址.
-   */
-  String GET_CALLBACK_IP_URL = "https://api.weixin.qq.com/cgi-bin/getcallbackip";
-  /**
-   * 第三方使用网站应用授权登录的url.
-   */
-  String QRCONNECT_URL = "https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect";
-  /**
-   * oauth2授权的url连接.
-   */
-  String CONNECT_OAUTH2_AUTHORIZE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s&connect_redirect=1#wechat_redirect";
-
-  /**
-   * 获取公众号的自动回复规则.
-   */
-  String GET_CURRENT_AUTOREPLY_INFO_URL = "https://api.weixin.qq.com/cgi-bin/get_current_autoreply_info";
-
-  /**
-   * 公众号调用或第三方平台帮公众号调用对公众号的所有api调用(包括第三方帮其调用)次数进行清零.
-   */
-  String CLEAR_QUOTA_URL = "https://api.weixin.qq.com/cgi-bin/clear_quota";
-
   /**
    * 
    * 验证消息的确来自微信服务器.
@@ -158,7 +103,7 @@ public interface WxMpService {
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=长链接转短链接接口
    * 
*/ - String shortUrl(String long_url) throws WxErrorException; + String shortUrl(String longUrl) throws WxErrorException; /** *
@@ -264,11 +209,21 @@ public interface WxMpService {
 
   /**
    * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求.
+   *
+   * @param queryParam 参数
+   * @param url        请求接口地址
+   * @return 接口响应字符串
+   * @throws WxErrorException 异常
    */
   String get(String url, String queryParam) throws WxErrorException;
 
   /**
    * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求.
+   *
+   * @param postData 请求参数json值
+   * @param url      请求接口地址
+   * @return 接口响应字符串
+   * @throws WxErrorException 异常
    */
   String post(String url, String postData) throws WxErrorException;
 
@@ -278,14 +233,54 @@ public interface WxMpService {
    * 比{@link #get}和{@link #post}方法更灵活,可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。
    * 可以参考,{@link MediaUploadRequestExecutor}的实现方法
    * 
+ * + * @param data 参数数据 + * @param executor 执行器 + * @param url 接口地址 + * @return 结果 + * @throws WxErrorException 异常 + */ + T execute(RequestExecutor executor, String url, E data) throws WxErrorException; + + /** + * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求. + * + * @param queryParam 参数 + * @param url 请求接口地址 + * @return 接口响应字符串 + * @throws WxErrorException 异常 + */ + String get(WxMpApiUrl url, String queryParam) throws WxErrorException; + + /** + * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求. + * + * @param postData 请求参数json值 + * @param url 请求接口地址 + * @return 接口响应字符串 + * @throws WxErrorException 异常 */ - T execute(RequestExecutor executor, String uri, E data) throws WxErrorException; + String post(WxMpApiUrl url, String postData) throws WxErrorException; /** *
+   * Service没有实现某个API的时候,可以用这个,
+   * 比{@link #get}和{@link #post}方法更灵活,可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。
+   * 可以参考,{@link MediaUploadRequestExecutor}的实现方法
+   * 
+ * + * @param data 参数数据 + * @param executor 执行器 + * @param url 接口地址 + * @return 结果 + * @throws WxErrorException 异常 + */ + T execute(RequestExecutor executor, WxMpApiUrl url, E data) throws WxErrorException; + + /** * 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试. + * * @param retrySleepMillis 默认:1000ms - *
*/ void setRetrySleepMillis(int retrySleepMillis); @@ -311,12 +306,14 @@ public interface WxMpService { /** * {@link Map} 加入新的 {@link WxMpConfigStorage},适用于动态添加新的微信公众号配置 + * * @param configStorage 新的微信配置 */ void addConfigStorage(String mpId, WxMpConfigStorage configStorage); /** * 从{@link Map} 移除 {@link String mpId} 所对应的 {@link WxMpConfigStorage},适用于动态移除微信公众号配置 + * * @param mpId 对应公众号的标识 */ void removeConfigStorage(String mpId); @@ -324,19 +321,22 @@ public interface WxMpService { /** * 注入多个 {@link WxMpConfigStorage} 的实现. 并为每个 {@link WxMpConfigStorage} 赋予不同的 {@link String mpId} 值 * 随机采用一个{@link String mpId}进行Http初始化操作 + * * @param configStorages WxMpConfigStorage map */ void setMultiConfigStorages(Map configStorages); /** * 注入多个 {@link WxMpConfigStorage} 的实现. 并为每个 {@link WxMpConfigStorage} 赋予不同的 {@link String label} 值 + * * @param configStorages WxMpConfigStorage map - * @param defaultMpId 设置一个{@link WxMpConfigStorage} 所对应的{@link String mpId}进行Http初始化 + * @param defaultMpId 设置一个{@link WxMpConfigStorage} 所对应的{@link String mpId}进行Http初始化 */ void setMultiConfigStorages(Map configStorages, String defaultMpId); /** * 进行相应的公众号切换 + * * @param mpId 公众号标识 * @return 切换是否成功 */ @@ -344,6 +344,7 @@ public interface WxMpService { /** * 进行相应的公众号切换 + * * @param mpId 公众号标识 * @return 切换成功,则返回当前对象,方便链式调用,否则抛出异常 */ diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpShakeService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpShakeService.java index 1f6c3052e7..8c45dadea0 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpShakeService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpShakeService.java @@ -7,12 +7,11 @@ import me.chanjar.weixin.mp.bean.shake.*; /** - * 摇一摇周边的相关接口 + * 摇一摇周边的相关接口. * * @author rememberber */ public interface WxMpShakeService { - /** *
    * 获取设备及用户信息
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java index 7b0913e688..82eaa5eeb5 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java @@ -8,20 +8,12 @@ import java.util.List; /** - * 门店管理的相关接口代码 - *

+ * 门店管理的相关接口代码. * Created by Binary Wang on 2016-09-23. * * @author Binary Wang */ public interface WxMpStoreService { - String POI_GET_WX_CATEGORY_URL = "https://api.weixin.qq.com/cgi-bin/poi/getwxcategory"; - String POI_UPDATE_URL = "https://api.weixin.qq.com/cgi-bin/poi/updatepoi"; - String POI_LIST_URL = "https://api.weixin.qq.com/cgi-bin/poi/getpoilist"; - String POI_DEL_URL = "https://api.weixin.qq.com/cgi-bin/poi/delpoi"; - String POI_GET_URL = "https://api.weixin.qq.com/cgi-bin/poi/getpoi"; - String POI_ADD_URL = "https://api.weixin.qq.com/cgi-bin/poi/addpoi"; - /** *

    * 创建门店
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpSubscribeMsgService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpSubscribeMsgService.java
index 1e91d9a2d6..549018e63b 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpSubscribeMsgService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpSubscribeMsgService.java
@@ -13,7 +13,6 @@
  * @date 2018-01-22 上午11:07
  */
 public interface WxMpSubscribeMsgService {
-
   /**
    * 
    * 构造用户订阅一条模板消息授权的url连接
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpTemplateMsgService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpTemplateMsgService.java
index f57c469c01..656840cbfa 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpTemplateMsgService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpTemplateMsgService.java
@@ -17,7 +17,6 @@
  * 
*/ public interface WxMpTemplateMsgService { - /** *
    * 设置所属行业
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java
index 71b6b17092..00eea89e74 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java
@@ -1,25 +1,19 @@
 package me.chanjar.weixin.mp.api;
 
-import java.util.List;
-
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.mp.bean.WxMpUserQuery;
 import me.chanjar.weixin.mp.bean.result.WxMpChangeOpenid;
 import me.chanjar.weixin.mp.bean.result.WxMpUser;
 import me.chanjar.weixin.mp.bean.result.WxMpUserList;
 
+import java.util.List;
+
 /**
  * 用户管理相关操作接口.
  *
  * @author Binary Wang
  */
 public interface WxMpUserService {
-  String USER_INFO_BATCH_GET_URL = "https://api.weixin.qq.com/cgi-bin/user/info/batchget";
-  String USER_GET_URL = "https://api.weixin.qq.com/cgi-bin/user/get";
-  String USER_INFO_URL = "https://api.weixin.qq.com/cgi-bin/user/info";
-  String USER_INFO_UPDATE_REMARK_URL = "https://api.weixin.qq.com/cgi-bin/user/info/updateremark";
-  String USER_CHANGE_OPENID_URL = "http://api.weixin.qq.com/cgi-bin/changeopenid";
-
   /**
    * 
    * 设置用户备注名
@@ -87,7 +81,9 @@ public interface WxMpUserService {
   /**
    * 
    * 获取用户列表
-   * 公众号可通过本接口来获取帐号的关注者列表,关注者列表由一串OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的)组成。一次拉取调用最多拉取10000个关注者的OpenID,可以通过多次拉取的方式来满足需求。
+   * 公众号可通过本接口来获取帐号的关注者列表,
+   * 关注者列表由一串OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的)组成。
+   * 一次拉取调用最多拉取10000个关注者的OpenID,可以通过多次拉取的方式来满足需求。
    * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140840&token=&lang=zh_CN
    * http请求方式: GET(请使用https协议)
    * 接口地址:https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID
@@ -101,11 +97,12 @@ public interface WxMpUserService {
    * 
    * 微信公众号主体变更迁移用户 openid
    * 详情请见: http://kf.qq.com/faq/170221aUnmmU170221eUZJNf.html
+   * http://kf.qq.com/faq/1901177NrqMr190117nqYJze.html
    * http请求方式: POST
    * 接口地址:https://api.weixin.qq.com/cgi-bin/changeopenid?access_token=ACCESS_TOKEN
    * 
* - * @param fromAppid 原公众号的 appid + * @param fromAppid 原公众号的 appid * @param openidList 需要转换的openid,这些必须是旧账号目前关注的才行,否则会出错;一次最多100个 */ List changeOpenid(String fromAppid, List openidList) throws WxErrorException; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserTagService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserTagService.java index 031585053e..c1549aff41 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserTagService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserTagService.java @@ -13,7 +13,6 @@ * @author Binary Wang */ public interface WxMpUserTagService { - /** *
    * 创建标签
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java
index 534ea1390f..28b69b98f7 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java
@@ -6,6 +6,7 @@
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
+import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.bean.WxJsapiSignature;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
@@ -22,25 +23,25 @@
 import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult;
 import me.chanjar.weixin.mp.bean.result.WxMpUser;
 import me.chanjar.weixin.mp.enums.TicketType;
+import me.chanjar.weixin.mp.enums.WxMpApiUrl;
 import me.chanjar.weixin.mp.util.WxMpConfigStorageHolder;
 import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.util.Map;
 import java.util.concurrent.locks.Lock;
 
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.*;
+
 /**
  * 基础实现类.
  *
  * @author someone
  */
+@Slf4j
 public abstract class BaseWxMpServiceImpl implements WxMpService, RequestHttp {
   private static final JsonParser JSON_PARSER = new JsonParser();
 
-  protected final Logger log = LoggerFactory.getLogger(this.getClass());
-
   protected WxSessionManager sessionManager = new StandardSessionManager();
   private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this);
   private WxMpMaterialService materialService = new WxMpMaterialServiceImpl(this);
@@ -73,7 +74,7 @@ public boolean checkSignature(String timestamp, String nonce, String signature)
       return SHA1.gen(this.getWxMpConfigStorage().getToken(), timestamp, nonce)
         .equals(signature);
     } catch (Exception e) {
-      this.log.error("Checking signature failed, and the reason is :" + e.getMessage());
+      log.error("Checking signature failed, and the reason is :" + e.getMessage());
       return false;
     }
   }
@@ -94,7 +95,7 @@ public String getTicket(TicketType type, boolean forceRefresh) throws WxErrorExc
 
       if (this.getWxMpConfigStorage().isTicketExpired(type)) {
         String responseContent = execute(SimpleGetRequestExecutor.create(this),
-          WxMpService.GET_TICKET_URL + type.getCode(), null);
+          GET_TICKET_URL + type.getCode(), null);
         JsonObject tmpJsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject();
         String jsapiTicket = tmpJsonObject.get("ticket").getAsString();
         int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
@@ -143,27 +144,27 @@ public String shortUrl(String longUrl) throws WxErrorException {
     JsonObject o = new JsonObject();
     o.addProperty("action", "long2short");
     o.addProperty("long_url", longUrl);
-    String responseContent = this.post(WxMpService.SHORTURL_API_URL, o.toString());
+    String responseContent = this.post(SHORTURL_API_URL, o.toString());
     JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent);
     return tmpJsonElement.getAsJsonObject().get("short_url").getAsString();
   }
 
   @Override
   public WxMpSemanticQueryResult semanticQuery(WxMpSemanticQuery semanticQuery) throws WxErrorException {
-    String responseContent = this.post(WxMpService.SEMANTIC_SEMPROXY_SEARCH_URL, semanticQuery.toJson());
+    String responseContent = this.post(SEMANTIC_SEMPROXY_SEARCH_URL, semanticQuery.toJson());
     return WxMpSemanticQueryResult.fromJson(responseContent);
   }
 
   @Override
   public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state) {
-    return String.format(WxMpService.CONNECT_OAUTH2_AUTHORIZE_URL,
+    return String.format(CONNECT_OAUTH2_AUTHORIZE_URL.getUrl(),
       this.getWxMpConfigStorage().getAppId(), URIUtil.encodeURIComponent(redirectURI), scope, StringUtils.trimToEmpty(state));
   }
 
   @Override
   public String buildQrConnectUrl(String redirectURI, String scope, String state) {
-    return String.format(WxMpService.QRCONNECT_URL,
-      this.getWxMpConfigStorage().getAppId(), URIUtil.encodeURIComponent(redirectURI), scope, StringUtils.trimToEmpty(state));
+    return String.format(QRCONNECT_URL.getUrl(), this.getWxMpConfigStorage().getAppId(),
+      URIUtil.encodeURIComponent(redirectURI), scope, StringUtils.trimToEmpty(state));
   }
 
   private WxMpOAuth2AccessToken getOAuth2AccessToken(String url) throws WxErrorException {
@@ -178,13 +179,14 @@ private WxMpOAuth2AccessToken getOAuth2AccessToken(String url) throws WxErrorExc
 
   @Override
   public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException {
-    String url = String.format(WxMpService.OAUTH2_ACCESS_TOKEN_URL, this.getWxMpConfigStorage().getAppId(), this.getWxMpConfigStorage().getSecret(), code);
+    String url = String.format(OAUTH2_ACCESS_TOKEN_URL.getUrl(), this.getWxMpConfigStorage().getAppId(),
+      this.getWxMpConfigStorage().getSecret(), code);
     return this.getOAuth2AccessToken(url);
   }
 
   @Override
   public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException {
-    String url = String.format(WxMpService.OAUTH2_REFRESH_TOKEN_URL, this.getWxMpConfigStorage().getAppId(), refreshToken);
+    String url = String.format(OAUTH2_REFRESH_TOKEN_URL.getUrl(), this.getWxMpConfigStorage().getAppId(), refreshToken);
     return this.getOAuth2AccessToken(url);
   }
 
@@ -194,7 +196,7 @@ public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken token, String lang) thro
       lang = "zh_CN";
     }
 
-    String url = String.format(WxMpService.OAUTH2_USERINFO_URL, token.getAccessToken(), token.getOpenId(), lang);
+    String url = String.format(OAUTH2_USERINFO_URL.getUrl(), token.getAccessToken(), token.getOpenId(), lang);
 
     try {
       RequestExecutor executor = SimpleGetRequestExecutor.create(this);
@@ -207,7 +209,7 @@ public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken token, String lang) thro
 
   @Override
   public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken token) {
-    String url = String.format(WxMpService.OAUTH2_VALIDATE_TOKEN_URL, token.getAccessToken(), token.getOpenId());
+    String url = String.format(OAUTH2_VALIDATE_TOKEN_URL.getUrl(), token.getAccessToken(), token.getOpenId());
 
     try {
       SimpleGetRequestExecutor.create(this).execute(url, null);
@@ -221,7 +223,7 @@ public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken token) {
 
   @Override
   public String[] getCallbackIP() throws WxErrorException {
-    String responseContent = this.get(WxMpService.GET_CALLBACK_IP_URL, null);
+    String responseContent = this.get(GET_CALLBACK_IP_URL, null);
     JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent);
     JsonArray ipList = tmpJsonElement.getAsJsonObject().get("ip_list").getAsJsonArray();
     String[] ipArray = new String[ipList.size()];
@@ -248,11 +250,26 @@ public String get(String url, String queryParam) throws WxErrorException {
     return execute(SimpleGetRequestExecutor.create(this), url, queryParam);
   }
 
+  @Override
+  public String get(WxMpApiUrl url, String queryParam) throws WxErrorException {
+    return this.get(url.getUrl(), queryParam);
+  }
+
   @Override
   public String post(String url, String postData) throws WxErrorException {
     return execute(SimplePostRequestExecutor.create(this), url, postData);
   }
 
+  @Override
+  public String post(WxMpApiUrl url, String postData) throws WxErrorException {
+    return this.post(url.getUrl(), postData);
+  }
+
+  @Override
+  public  T execute(RequestExecutor executor, WxMpApiUrl url, E data) throws WxErrorException {
+    return this.execute(executor, url.getUrl(), data);
+  }
+
   /**
    * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求.
    */
@@ -264,7 +281,7 @@ public  T execute(RequestExecutor executor, String uri, E data) thro
         return this.executeInternal(executor, uri, data);
       } catch (WxErrorException e) {
         if (retryTimes + 1 > this.maxRetryTimes) {
-          this.log.warn("重试达到最大次数【{}】", maxRetryTimes);
+          log.warn("重试达到最大次数【{}】", maxRetryTimes);
           //最后一次重试失败后,直接抛出异常,不再等待
           throw new RuntimeException("微信服务端异常,超出重试次数");
         }
@@ -274,7 +291,7 @@ public  T execute(RequestExecutor executor, String uri, E data) thro
         if (error.getErrorCode() == -1) {
           int sleepMillis = this.retrySleepMillis * (1 << retryTimes);
           try {
-            this.log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
+            log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
             Thread.sleep(sleepMillis);
           } catch (InterruptedException e1) {
             throw new RuntimeException(e1);
@@ -285,11 +302,11 @@ public  T execute(RequestExecutor executor, String uri, E data) thro
       }
     } while (retryTimes++ < this.maxRetryTimes);
 
-    this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
+    log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
     throw new RuntimeException("微信服务端异常,超出重试次数");
   }
 
-  public  T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException {
+  protected  T executeInternal(RequestExecutor executor, String uri, E data) throws WxErrorException {
     E dataForLog = DataUtils.handleDataWithSecret(data);
 
     if (uri.contains("access_token=")) {
@@ -302,7 +319,7 @@ public  T executeInternal(RequestExecutor executor, String uri, E da
 
     try {
       T result = executor.execute(uriWithAccessToken, data);
-      this.log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result);
+      log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result);
       return result;
     } catch (WxErrorException e) {
       WxError error = e.getError();
@@ -321,12 +338,12 @@ public  T executeInternal(RequestExecutor executor, String uri, E da
       }
 
       if (error.getErrorCode() != 0) {
-        this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error);
+        log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error);
         throw new WxErrorException(error, e);
       }
       return null;
     } catch (IOException e) {
-      this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage());
+      log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage());
       throw new WxErrorException(WxError.builder().errorMsg(e.getMessage()).build(), e);
     }
   }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java
index 628b6c55f8..119376d621 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java
@@ -1,16 +1,20 @@
 package me.chanjar.weixin.mp.api.impl;
 
-import java.io.File;
-
 import com.google.gson.JsonParser;
+import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.mp.api.WxMpAiOpenService;
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.enums.AiLangType;
+import me.chanjar.weixin.mp.enums.WxMpApiUrl;
 import me.chanjar.weixin.mp.util.requestexecuter.voice.VoiceUploadRequestExecutor;
 
+import java.io.File;
+
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.AiOpen.*;
+
 /**
  * 
  *  Created by BinaryWang on 2018/6/9.
@@ -18,13 +22,10 @@
  *
  * @author Binary Wang
  */
+@RequiredArgsConstructor
 public class WxMpAiOpenServiceImpl implements WxMpAiOpenService {
   private static final JsonParser JSON_PARSER = new JsonParser();
-  private WxMpService wxMpService;
-
-  public WxMpAiOpenServiceImpl(WxMpService wxMpService) {
-    this.wxMpService = wxMpService;
-  }
+  private final WxMpService wxMpService;
 
   @Override
   public void uploadVoice(String voiceId, AiLangType lang, File voiceFile) throws WxErrorException {
@@ -33,7 +34,7 @@ public void uploadVoice(String voiceId, AiLangType lang, File voiceFile) throws
     }
 
     this.wxMpService.execute(VoiceUploadRequestExecutor.create(this.wxMpService.getRequestHttp()),
-      String.format(VOICE_UPLOAD_URL, "mp3", voiceId, lang.getCode()),
+      String.format(VOICE_UPLOAD_URL.getUrl(), "mp3", voiceId, lang.getCode()),
       voiceFile);
   }
 
@@ -45,7 +46,7 @@ public String recogniseVoice(String voiceId, AiLangType lang, File voiceFile) th
 
   @Override
   public String translate(AiLangType langFrom, AiLangType langTo, String content) throws WxErrorException {
-    String response = this.wxMpService.post(String.format(TRANSLATE_URL, langFrom.getCode(), langTo.getCode()), content);
+    String response = this.wxMpService.post(String.format(TRANSLATE_URL.getUrl(), langFrom.getCode(), langTo.getCode()), content);
 
     WxError error = WxError.fromJson(response, WxType.MP);
     if (error.getErrorCode() != 0) {
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 d96b9752d0..f232f1bb69 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
@@ -13,6 +13,7 @@
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.bean.card.*;
 import me.chanjar.weixin.mp.enums.TicketType;
+import me.chanjar.weixin.mp.enums.WxMpApiUrl;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -54,7 +55,7 @@ public String getCardApiTicket(boolean forceRefresh) throws WxErrorException {
 
       if (this.getWxMpService().getWxMpConfigStorage().isTicketExpired(type)) {
         String responseContent = this.wxMpService.execute(SimpleGetRequestExecutor
-          .create(this.getWxMpService().getRequestHttp()), CARD_GET_TICKET, null);
+          .create(this.getWxMpService().getRequestHttp()), WxMpApiUrl.Card.CARD_GET_TICKET, null);
         JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
         JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
         String cardApiTicket = tmpJsonObject.get("ticket").getAsString();
@@ -94,7 +95,7 @@ public WxCardApiSignature createCardApiSignature(String... optionalSignParam) th
   public String decryptCardCode(String encryptCode) throws WxErrorException {
     JsonObject param = new JsonObject();
     param.addProperty("encrypt_code", encryptCode);
-    String responseContent = this.wxMpService.post(CARD_CODE_DECRYPT, param.toString());
+    String responseContent = this.wxMpService.post(WxMpApiUrl.Card.CARD_CODE_DECRYPT, param.toString());
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
     JsonPrimitive jsonPrimitive = tmpJsonObject.getAsJsonPrimitive("code");
@@ -107,7 +108,7 @@ public WxMpCardResult queryCardCode(String cardId, String code, boolean checkCon
     param.addProperty("card_id", cardId);
     param.addProperty("code", code);
     param.addProperty("check_consume", checkConsume);
-    String responseContent = this.wxMpService.post(CARD_CODE_GET, param.toString());
+    String responseContent = this.wxMpService.post(WxMpApiUrl.Card.CARD_CODE_GET, param.toString());
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return WxMpGsonBuilder.create().fromJson(tmpJsonElement,
       new TypeToken() {
@@ -128,7 +129,7 @@ public String consumeCardCode(String code, String cardId) throws WxErrorExceptio
       param.addProperty("card_id", cardId);
     }
 
-    return this.wxMpService.post(CARD_CODE_CONSUME, param.toString());
+    return this.wxMpService.post(WxMpApiUrl.Card.CARD_CODE_CONSUME, param.toString());
   }
 
   @Override
@@ -138,7 +139,7 @@ public void markCardCode(String code, String cardId, String openId, boolean isMa
     param.addProperty("card_id", cardId);
     param.addProperty("openid", openId);
     param.addProperty("is_mark", isMark);
-    String responseContent = this.getWxMpService().post(CARD_CODE_MARK, param.toString());
+    String responseContent = this.getWxMpService().post(WxMpApiUrl.Card.CARD_CODE_MARK, param.toString());
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     WxMpCardResult cardResult = WxMpGsonBuilder.create().fromJson(tmpJsonElement,
       new TypeToken() {
@@ -152,7 +153,7 @@ public void markCardCode(String code, String cardId, String openId, boolean isMa
   public String getCardDetail(String cardId) throws WxErrorException {
     JsonObject param = new JsonObject();
     param.addProperty("card_id", cardId);
-    String responseContent = this.wxMpService.post(CARD_GET, param.toString());
+    String responseContent = this.wxMpService.post(WxMpApiUrl.Card.CARD_GET, param.toString());
 
     // 判断返回值
     JsonObject json = (new JsonParser()).parse(responseContent).getAsJsonObject();
@@ -173,12 +174,12 @@ public String addTestWhiteList(String openid) throws WxErrorException {
     array.add(openid);
     JsonObject jsonObject = new JsonObject();
     jsonObject.add("openid", array);
-    return this.wxMpService.post(CARD_TEST_WHITELIST, GSON.toJson(jsonObject));
+    return this.wxMpService.post(WxMpApiUrl.Card.CARD_TEST_WHITELIST, GSON.toJson(jsonObject));
   }
 
   @Override
   public WxMpCardCreateResult createCard(WxMpCardCreateMessage cardCreateMessage) throws WxErrorException {
-    String response = this.wxMpService.post(CARD_CREATE, GSON.toJson(cardCreateMessage));
+    String response = this.wxMpService.post(WxMpApiUrl.Card.CARD_CREATE, GSON.toJson(cardCreateMessage));
     return WxMpCardCreateResult.fromJson(response);
   }
 
@@ -200,12 +201,12 @@ public WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerSt
     cardJson.addProperty("outer_str", outerStr);
     actionInfoJson.add("card", cardJson);
     jsonObject.add("action_info", actionInfoJson);
-    return WxMpCardQrcodeCreateResult.fromJson(this.wxMpService.post(CARD_QRCODE_CREATE, GSON.toJson(jsonObject)));
+    return WxMpCardQrcodeCreateResult.fromJson(this.wxMpService.post(WxMpApiUrl.Card.CARD_QRCODE_CREATE, GSON.toJson(jsonObject)));
   }
 
   @Override
   public WxMpCardLandingPageCreateResult createLandingPage(WxMpCardLandingPageCreateRequest request) throws WxErrorException {
-    String response = this.wxMpService.post(CARD_LANDING_PAGE_CREATE, GSON.toJson(request));
+    String response = this.wxMpService.post(WxMpApiUrl.Card.CARD_LANDING_PAGE_CREATE, GSON.toJson(request));
     return WxMpCardLandingPageCreateResult.fromJson(response);
   }
 
@@ -218,7 +219,7 @@ public String unavailableCardCode(String cardId, String code, String reason) thr
     jsonRequest.addProperty("card_id", cardId);
     jsonRequest.addProperty("code", code);
     jsonRequest.addProperty("reason", reason);
-    return this.wxMpService.post(CARD_CODE_UNAVAILABLE, GSON.toJson(jsonRequest));
+    return this.wxMpService.post(WxMpApiUrl.Card.CARD_CODE_UNAVAILABLE, GSON.toJson(jsonRequest));
   }
 
   @Override
@@ -228,7 +229,7 @@ public WxMpCardDeleteResult deleteCard(String cardId) throws WxErrorException {
     }
     JsonObject param = new JsonObject();
     param.addProperty("card_id", cardId);
-    String response = this.wxMpService.post(CARD_DELETE, param.toString());
+    String response = this.wxMpService.post(WxMpApiUrl.Card.CARD_DELETE, param.toString());
     return WxMpCardDeleteResult.fromJson(response);
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDataCubeServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDataCubeServiceImpl.java
index bf60892a1b..a3523c0d77 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDataCubeServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDataCubeServiceImpl.java
@@ -1,30 +1,30 @@
 package me.chanjar.weixin.mp.api.impl;
 
 import com.google.gson.JsonObject;
+import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.mp.api.WxMpDataCubeService;
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.bean.datacube.*;
+import me.chanjar.weixin.mp.enums.WxMpApiUrl;
 import org.apache.commons.lang3.time.FastDateFormat;
 
 import java.text.Format;
 import java.util.Date;
 import java.util.List;
 
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.DataCube.*;
+
 /**
  * Created by Binary Wang on 2016/8/23.
  *
  * @author binarywang (https://github.com/binarywang)
  */
+@RequiredArgsConstructor
 public class WxMpDataCubeServiceImpl implements WxMpDataCubeService {
-
   private final Format dateFormat = FastDateFormat.getInstance("yyyy-MM-dd");
 
-  private WxMpService wxMpService;
-
-  public WxMpDataCubeServiceImpl(WxMpService wxMpService) {
-    this.wxMpService = wxMpService;
-  }
+  private final WxMpService wxMpService;
 
   @Override
   public List getUserSummary(Date beginDate, Date endDate) throws WxErrorException {
@@ -69,7 +69,7 @@ public List getUserShareHour(Date beginDate, Date endDa
     return this.getArticleResults(GET_USER_SHARE_HOUR, beginDate, endDate);
   }
 
-  private List getArticleResults(String url, Date beginDate, Date endDate) throws WxErrorException {
+  private List getArticleResults(WxMpApiUrl url, Date beginDate, Date endDate) throws WxErrorException {
     String responseContent = this.wxMpService.post(url, buildParams(beginDate, endDate));
     return WxDataCubeArticleResult.fromJson(responseContent);
   }
@@ -109,13 +109,13 @@ public List getUpstreamMsgDistMonth(Date beginDate, Date en
     return this.getUpstreamMsg(GET_UPSTREAM_MSG_DIST_MONTH, beginDate, endDate);
   }
 
-  private List getUpstreamMsg(String url, Date beginDate,                                                   Date endDate) throws WxErrorException {
+  private List getUpstreamMsg(WxMpApiUrl url, Date beginDate, Date endDate) throws WxErrorException {
     String responseContent = this.wxMpService.post(url, buildParams(beginDate, endDate));
     return WxDataCubeMsgResult.fromJson(responseContent);
   }
 
   @Override
-  public List getInterfaceSummary(Date beginDate,                                                             Date endDate) throws WxErrorException {
+  public List getInterfaceSummary(Date beginDate, Date endDate) throws WxErrorException {
     String responseContent = this.wxMpService.post(GET_INTERFACE_SUMMARY, buildParams(beginDate, endDate));
     return WxDataCubeInterfaceResult.fromJson(responseContent);
   }
@@ -128,7 +128,7 @@ private String buildParams(Date beginDate, Date endDate) {
   }
 
   @Override
-  public List getInterfaceSummaryHour(Date beginDate,                                                                 Date endDate) throws WxErrorException {
+  public List getInterfaceSummaryHour(Date beginDate, Date endDate) throws WxErrorException {
     String responseContent = this.wxMpService.post(GET_INTERFACE_SUMMARY_HOUR, buildParams(beginDate, endDate));
     return WxDataCubeInterfaceResult.fromJson(responseContent);
   }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDeviceServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDeviceServiceImpl.java
index 3fe464a89e..3aa122a533 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDeviceServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpDeviceServiceImpl.java
@@ -1,86 +1,76 @@
 package me.chanjar.weixin.mp.api.impl;
 
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.mp.api.WxMpDeviceService;
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.bean.device.*;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import me.chanjar.weixin.mp.enums.WxMpApiUrl;
+
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Device.*;
 
 /**
  * Created by keungtung on 10/12/2016.
+ *
+ * @author keungtung
  */
+@Slf4j
+@RequiredArgsConstructor
 public class WxMpDeviceServiceImpl implements WxMpDeviceService {
-  private static final String API_URL_PREFIX = "https://api.weixin.qq.com/device";
-  private static Logger log = LoggerFactory.getLogger(WxMpMenuServiceImpl.class);
-
-  private WxMpService wxMpService;
-
-  public WxMpDeviceServiceImpl(WxMpService wxMpService) {
-    this.wxMpService = wxMpService;
-  }
+  private final WxMpService wxMpService;
 
   @Override
   public TransMsgResp transMsg(WxDeviceMsg msg) throws WxErrorException {
-    String url = API_URL_PREFIX + "/transmsg";
-    String response = this.wxMpService.post(url, msg.toJson());
+    String response = this.wxMpService.post(DEVICE_TRANSMSG, msg.toJson());
     return TransMsgResp.fromJson(response);
   }
 
   @Override
   public WxDeviceQrCodeResult getQrCode(String productId) throws WxErrorException {
-    String url = API_URL_PREFIX + "/getqrcode";
-    String response = this.wxMpService.get(url, "product_id=" + productId);
+    String response = this.wxMpService.get(DEVICE_GETQRCODE, "product_id=" + productId);
     return WxDeviceQrCodeResult.fromJson(response);
   }
 
   @Override
   public WxDeviceAuthorizeResult authorize(WxDeviceAuthorize wxDeviceAuthorize) throws WxErrorException {
-    String url = API_URL_PREFIX + "/authorize_device";
-    String response = this.wxMpService.post(url, wxDeviceAuthorize.toJson());
+    String response = this.wxMpService.post(DEVICE_AUTHORIZE_DEVICE, wxDeviceAuthorize.toJson());
     return WxDeviceAuthorizeResult.fromJson(response);
   }
 
   @Override
   public WxDeviceBindResult bind(WxDeviceBind wxDeviceBind) throws WxErrorException {
-    String url = API_URL_PREFIX + "/bind";
-    String response = this.wxMpService.post(url, wxDeviceBind.toJson());
+    String response = this.wxMpService.post(DEVICE_BIND, wxDeviceBind.toJson());
     return WxDeviceBindResult.fromJson(response);
   }
 
   @Override
   public WxDeviceBindResult compelBind(WxDeviceBind wxDeviceBind) throws WxErrorException {
-    String url = API_URL_PREFIX + "/compel_bind";
-    String response = this.wxMpService.post(url, wxDeviceBind.toJson());
+    String response = this.wxMpService.post(DEVICE_COMPEL_BIND, wxDeviceBind.toJson());
     return WxDeviceBindResult.fromJson(response);
   }
 
   @Override
   public WxDeviceBindResult unbind(WxDeviceBind wxDeviceBind) throws WxErrorException {
-    String url = API_URL_PREFIX + "/unbind?";
-    String response = this.wxMpService.post(url, wxDeviceBind.toJson());
+    String response = this.wxMpService.post(DEVICE_UNBIND, wxDeviceBind.toJson());
     return WxDeviceBindResult.fromJson(response);
   }
 
   @Override
   public WxDeviceBindResult compelUnbind(WxDeviceBind wxDeviceBind) throws WxErrorException {
-    String url = API_URL_PREFIX + "/compel_unbind?";
-    String response = this.wxMpService.post(url, wxDeviceBind.toJson());
+    String response = this.wxMpService.post(DEVICE_COMPEL_UNBIND, wxDeviceBind.toJson());
     return WxDeviceBindResult.fromJson(response);
   }
 
   @Override
   public WxDeviceOpenIdResult getOpenId(String deviceType, String deviceId) throws WxErrorException {
-    String url = API_URL_PREFIX + "/get_openid";
-    String response = this.wxMpService.get(url, "device_type=" + deviceType + "&device_id=" + deviceId);
+    String response = this.wxMpService.get(DEVICE_GET_OPENID, "device_type=" + deviceType + "&device_id=" + deviceId);
     return WxDeviceOpenIdResult.fromJson(response);
   }
 
   @Override
   public WxDeviceBindDeviceResult getBindDevice(String openId) throws WxErrorException {
-    String url = API_URL_PREFIX + "/get_bind_device";
-    String response = this.wxMpService.get(url, "openid=" + openId);
+    String response = this.wxMpService.get(DEVICE_GET_BIND_DEVICE, "openid=" + openId);
     return WxDeviceBindDeviceResult.fromJson(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 7707c567dd..4743cc247a 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,12 +1,8 @@
 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 lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
@@ -16,23 +12,21 @@
 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.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;
+import me.chanjar.weixin.mp.bean.kefu.result.*;
+import me.chanjar.weixin.mp.enums.WxMpApiUrl;
+
+import java.io.File;
+import java.util.Date;
+
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Kefu.*;
 
 /**
  * @author Binary Wang
  */
+@Slf4j
+@RequiredArgsConstructor
 public class WxMpKefuServiceImpl implements WxMpKefuService {
-  protected final Logger log = LoggerFactory.getLogger(this.getClass());
-  private WxMpService wxMpService;
-
-  public WxMpKefuServiceImpl(WxMpService wxMpService) {
-    this.wxMpService = wxMpService;
-  }
+  private final WxMpService wxMpService;
 
   @Override
   public boolean sendKefuMessage(WxMpKefuMessage message) throws WxErrorException {
@@ -73,13 +67,14 @@ public boolean kfAccountInviteWorker(WxMpKfAccountRequest request) throws WxErro
   @Override
   public boolean kfAccountUploadHeadImg(String kfAccount, File imgFile) throws WxErrorException {
     WxMediaUploadResult responseContent = this.wxMpService
-      .execute(MediaUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), String.format(KFACCOUNT_UPLOAD_HEAD_IMG, kfAccount), imgFile);
+      .execute(MediaUploadRequestExecutor.create(this.wxMpService.getRequestHttp()),
+        String.format(KFACCOUNT_UPLOAD_HEAD_IMG.getUrl(), kfAccount), imgFile);
     return responseContent != null;
   }
 
   @Override
   public boolean kfAccountDel(String kfAccount) throws WxErrorException {
-    String responseContent = this.wxMpService.get(String.format(KFACCOUNT_DEL, kfAccount), null);
+    String responseContent = this.wxMpService.get(String.format(KFACCOUNT_DEL.getUrl(), kfAccount), null);
     return responseContent != null;
   }
 
@@ -99,13 +94,13 @@ public boolean kfSessionClose(String openid, String kfAccount) throws WxErrorExc
 
   @Override
   public WxMpKfSessionGetResult kfSessionGet(String openid) throws WxErrorException {
-    String responseContent = this.wxMpService.get(String.format(KFSESSION_GET_SESSION, openid), null);
+    String responseContent = this.wxMpService.get(String.format(KFSESSION_GET_SESSION.getUrl(), openid), null);
     return WxMpKfSessionGetResult.fromJson(responseContent);
   }
 
   @Override
   public WxMpKfSessionList kfSessionList(String kfAccount) throws WxErrorException {
-    String responseContent = this.wxMpService.get(String.format(KFSESSION_GET_SESSION_LIST, kfAccount), null);
+    String responseContent = this.wxMpService.get(String.format(KFSESSION_GET_SESSION_LIST.getUrl(), kfAccount), null);
     return WxMpKfSessionList.fromJson(responseContent);
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMarketingServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMarketingServiceImpl.java
index 91e7d4c1ba..5f2ece51fe 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMarketingServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMarketingServiceImpl.java
@@ -4,6 +4,8 @@
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.mp.api.WxMpMarketingService;
 import me.chanjar.weixin.mp.api.WxMpService;
@@ -12,8 +14,6 @@
 import me.chanjar.weixin.mp.bean.marketing.WxMpUserAction;
 import me.chanjar.weixin.mp.bean.marketing.WxMpUserActionSet;
 import org.apache.commons.lang3.time.DateFormatUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.net.URLEncoder;
@@ -21,44 +21,40 @@
 import java.util.Date;
 import java.util.List;
 
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Marketing.*;
+
 /**
  * @author 007
  */
+@Slf4j
+@RequiredArgsConstructor
 public class WxMpMarketingServiceImpl implements WxMpMarketingService {
-  protected final Logger log = LoggerFactory.getLogger(this.getClass());
-  private WxMpService wxMpService;
-
-  public WxMpMarketingServiceImpl(WxMpService wxMpService) {
-    this.wxMpService = wxMpService;
-  }
+  private final WxMpService wxMpService;
 
   @Override
   public long addUserActionSets(String type, String name, String description) throws WxErrorException {
-    String url = API_URL_PREFIX + "user_action_sets/add?version=v1.0";
     JsonObject json = new JsonObject();
     json.addProperty("type", type);
     json.addProperty("name", name);
     json.addProperty("description", description);
-    String responseContent = wxMpService.post(url, json.toString());
+    String responseContent = wxMpService.post(USER_ACTION_SETS_ADD, json.toString());
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return tmpJsonElement.getAsJsonObject().get("data").getAsJsonObject().get("user_action_set_id").getAsLong();
   }
 
   @Override
   public List getUserActionSets(Long userActionSetId) throws WxErrorException {
-    String url = API_URL_PREFIX + "user_action_sets/get";
-    String responseContent = wxMpService.get(url, "version=v1.0&user_action_set_id=" + userActionSetId);
+    String responseContent = wxMpService.get(USER_ACTION_SETS_GET, "version=v1.0&user_action_set_id=" + userActionSetId);
     return WxMpUserActionSet.fromJson(responseContent);
   }
 
   @Override
   public void addUserAction(List actions) throws WxErrorException {
-    String url = API_URL_PREFIX + "user_actions/add?version=v1.0";
     JsonArray json = new JsonArray();
     for (WxMpUserAction action : actions) {
       json.add(action.toJsonObject());
     }
-    wxMpService.post(url, json.toString());
+    wxMpService.post(USER_ACTIONS_ADD, json.toString());
   }
 
   @Override
@@ -70,7 +66,6 @@ public WxMpAdLeadResult getAdLeads(Date beginDate, Date endDate, List
@@ -18,41 +19,38 @@
  *
  * @author Binary Wang
  */
+@Slf4j
+@RequiredArgsConstructor
 public class WxMpMassMessageServiceImpl implements WxMpMassMessageService {
-  protected final Logger log = LoggerFactory.getLogger(this.getClass());
-  private WxMpService wxMpService;
-
-  public WxMpMassMessageServiceImpl(WxMpService wxMpService) {
-    this.wxMpService = wxMpService;
-  }
+  private final WxMpService wxMpService;
 
   @Override
   public WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException {
-    String responseContent = this.wxMpService.post(MEDIA_UPLOAD_NEWS_URL, news.toJson());
+    String responseContent = this.wxMpService.post(WxMpApiUrl.MassMessage.MEDIA_UPLOAD_NEWS_URL, news.toJson());
     return WxMpMassUploadResult.fromJson(responseContent);
   }
 
   @Override
   public WxMpMassUploadResult massVideoUpload(WxMpMassVideo video) throws WxErrorException {
-    String responseContent = this.wxMpService.post(MEDIA_UPLOAD_VIDEO_URL, video.toJson());
+    String responseContent = this.wxMpService.post(WxMpApiUrl.MassMessage.MEDIA_UPLOAD_VIDEO_URL, video.toJson());
     return WxMpMassUploadResult.fromJson(responseContent);
   }
 
   @Override
   public WxMpMassSendResult massGroupMessageSend(WxMpMassTagMessage message) throws WxErrorException {
-    String responseContent = this.wxMpService.post(WxMpMassMessageService.MESSAGE_MASS_SENDALL_URL, message.toJson());
+    String responseContent = this.wxMpService.post(WxMpApiUrl.MassMessage.MESSAGE_MASS_SENDALL_URL, message.toJson());
     return WxMpMassSendResult.fromJson(responseContent);
   }
 
   @Override
   public WxMpMassSendResult massOpenIdsMessageSend(WxMpMassOpenIdsMessage message) throws WxErrorException {
-    String responseContent = this.wxMpService.post(MESSAGE_MASS_SEND_URL, message.toJson());
+    String responseContent = this.wxMpService.post(WxMpApiUrl.MassMessage.MESSAGE_MASS_SEND_URL, message.toJson());
     return WxMpMassSendResult.fromJson(responseContent);
   }
 
   @Override
   public WxMpMassSendResult massMessagePreview(WxMpMassPreviewMessage wxMpMassPreviewMessage) throws WxErrorException {
-    String responseContent = this.wxMpService.post(MESSAGE_MASS_PREVIEW_URL, wxMpMassPreviewMessage.toJson());
+    String responseContent = this.wxMpService.post(WxMpApiUrl.MassMessage.MESSAGE_MASS_PREVIEW_URL, wxMpMassPreviewMessage.toJson());
     return WxMpMassSendResult.fromJson(responseContent);
   }
 
@@ -61,7 +59,7 @@ public void delete(Long msgId, Integer articleIndex) throws WxErrorException {
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("msg_id", msgId);
     jsonObject.addProperty("article_idx", articleIndex);
-    this.wxMpService.post(MESSAGE_MASS_DELETE_URL, jsonObject.toString());
+    this.wxMpService.post(WxMpApiUrl.MassMessage.MESSAGE_MASS_DELETE_URL, jsonObject.toString());
   }
 
 }
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 7929aced0a..3352b95e21 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,12 +1,6 @@
 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 lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.WxType;
 import me.chanjar.weixin.common.api.WxConsts;
 import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
@@ -18,33 +12,29 @@
 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.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.bean.material.*;
+import me.chanjar.weixin.mp.enums.WxMpApiUrl;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
-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.material.*;
 import me.chanjar.weixin.mp.util.requestexecuter.media.MediaImgUploadRequestExecutor;
 
+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 static me.chanjar.weixin.mp.enums.WxMpApiUrl.Material.*;
+
 /**
  * Created by Binary Wang on 2016/7/21.
+ *
+ * @author Binary Wang
  */
+@RequiredArgsConstructor
 public class WxMpMaterialServiceImpl implements WxMpMaterialService {
-
-  private WxMpService wxMpService;
-
-  public WxMpMaterialServiceImpl(WxMpService wxMpService) {
-    this.wxMpService = wxMpService;
-  }
+  private final WxMpService wxMpService;
 
   @Override
   public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) throws WxErrorException {
@@ -63,7 +53,7 @@ public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputS
 
   @Override
   public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException {
-    String url = String.format(MEDIA_UPLOAD_URL, mediaType);
+    String url = String.format(MEDIA_UPLOAD_URL.getUrl(), mediaType);
     return this.wxMpService.execute(MediaUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), url, file);
   }
 
@@ -82,7 +72,7 @@ public WxMediaImgUploadResult mediaImgUpload(File file) throws WxErrorException
 
   @Override
   public WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMaterial material) throws WxErrorException {
-    String url = String.format(MATERIAL_ADD_URL, mediaType);
+    String url = String.format(MATERIAL_ADD_URL.getUrl(), mediaType);
     return this.wxMpService.execute(MaterialUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), url, material);
   }
 
@@ -98,17 +88,20 @@ public WxMpMaterialUploadResult materialNewsUpload(WxMpMaterialNews news) throws
   @Override
   public InputStream materialImageOrVoiceDownload(String mediaId) throws WxErrorException {
     return this.wxMpService.execute(MaterialVoiceAndImageDownloadRequestExecutor
-      .create(this.wxMpService.getRequestHttp(), this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), MATERIAL_GET_URL, mediaId);
+      .create(this.wxMpService.getRequestHttp(), this.wxMpService.getWxMpConfigStorage().getTmpDirFile()),
+      MATERIAL_GET_URL, mediaId);
   }
 
   @Override
   public WxMpMaterialVideoInfoResult materialVideoInfo(String mediaId) throws WxErrorException {
-    return this.wxMpService.execute(MaterialVideoInfoRequestExecutor.create(this.wxMpService.getRequestHttp()), MATERIAL_GET_URL, mediaId);
+    return this.wxMpService.execute(MaterialVideoInfoRequestExecutor.create(this.wxMpService.getRequestHttp()),
+      MATERIAL_GET_URL, mediaId);
   }
 
   @Override
   public WxMpMaterialNews materialNewsInfo(String mediaId) throws WxErrorException {
-    return this.wxMpService.execute(MaterialNewsInfoRequestExecutor.create(this.wxMpService.getRequestHttp()), MATERIAL_GET_URL, mediaId);
+    return this.wxMpService.execute(MaterialNewsInfoRequestExecutor.create(this.wxMpService.getRequestHttp()),
+      MATERIAL_GET_URL, mediaId);
   }
 
   @Override
@@ -124,7 +117,8 @@ public boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleU
 
   @Override
   public boolean materialDelete(String mediaId) throws WxErrorException {
-    return this.wxMpService.execute(MaterialDeleteRequestExecutor.create(this.wxMpService.getRequestHttp()), MATERIAL_DEL_URL, mediaId);
+    return this.wxMpService.execute(MaterialDeleteRequestExecutor.create(this.wxMpService.getRequestHttp()),
+      MATERIAL_DEL_URL, mediaId);
   }
 
   @Override
@@ -140,7 +134,7 @@ public WxMpMaterialCountResult materialCount() throws WxErrorException {
 
   @Override
   public WxMpMaterialNewsBatchGetResult materialNewsBatchGet(int offset, int count) throws WxErrorException {
-    Map params = new HashMap<>();
+    Map params = new HashMap<>(4);
     params.put("type", WxConsts.MaterialType.NEWS);
     params.put("offset", offset);
     params.put("count", count);
@@ -155,7 +149,7 @@ public WxMpMaterialNewsBatchGetResult materialNewsBatchGet(int offset, int count
 
   @Override
   public WxMpMaterialFileBatchGetResult materialFileBatchGet(String type, int offset, int count) throws WxErrorException {
-    Map params = new HashMap<>();
+    Map params = new HashMap<>(4);
     params.put("type", type);
     params.put("offset", offset);
     params.put("count", count);
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 3eaf61417c..31d9bcf373 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
@@ -5,7 +5,9 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.mp.bean.membercard.*;
+import me.chanjar.weixin.mp.enums.WxMpApiUrl;
 import org.apache.commons.lang3.StringUtils;
 
 import com.google.gson.Gson;
@@ -40,15 +42,12 @@
  * @version 2017/7/8
  */
 @Slf4j
+@RequiredArgsConstructor
 public class WxMpMemberCardServiceImpl implements WxMpMemberCardService {
-  private WxMpService wxMpService;
+  private final WxMpService wxMpService;
 
   private static final Gson GSON = WxMpGsonBuilder.create();
 
-  public WxMpMemberCardServiceImpl(WxMpService wxMpService) {
-    this.wxMpService = wxMpService;
-  }
-
   @Override
   public WxMpService getWxMpService() {
     return this.wxMpService;
@@ -70,7 +69,7 @@ public WxMpCardCreateResult createMemberCard(WxMpMemberCardCreateMessage createM
       return validResult;
     }
 
-    String response = this.wxMpService.post(MEMBER_CARD_CREATE, GSON.toJson(createMessageMessage));
+    String response = this.wxMpService.post(WxMpApiUrl.MemberCard.MEMBER_CARD_CREATE, GSON.toJson(createMessageMessage));
     return WxMpCardCreateResult.fromJson(response);
   }
 
@@ -212,7 +211,7 @@ private WxMpCardCreateResult validCheck(WxMpMemberCardCreateMessage createMessag
 
   @Override
   public String activateMemberCard(WxMpMemberCardActivatedMessage activatedMessage) throws WxErrorException {
-    return this.wxMpService.post(MEMBER_CARD_ACTIVATE, GSON.toJson(activatedMessage));
+    return this.wxMpService.post(WxMpApiUrl.MemberCard.MEMBER_CARD_ACTIVATE, GSON.toJson(activatedMessage));
   }
 
   @Override
@@ -221,7 +220,7 @@ public WxMpMemberCardUserInfoResult getUserInfo(String cardId, String code) thro
     jsonObject.addProperty("card_id", cardId);
     jsonObject.addProperty("code", code);
 
-    String responseContent = this.getWxMpService().post(MEMBER_CARD_USER_INFO_GET, jsonObject.toString());
+    String responseContent = this.getWxMpService().post(WxMpApiUrl.MemberCard.MEMBER_CARD_USER_INFO_GET, jsonObject.toString());
     log.debug("{}", responseContent);
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return WxMpGsonBuilder.create().fromJson(tmpJsonElement,
@@ -233,7 +232,7 @@ public WxMpMemberCardUserInfoResult getUserInfo(String cardId, String code) thro
   public WxMpMemberCardUpdateResult updateUserMemberCard(WxMpMemberCardUpdateMessage updateUserMessage)
     throws WxErrorException {
 
-    String responseContent = this.getWxMpService().post(MEMBER_CARD_UPDATE_USER, GSON.toJson(updateUserMessage));
+    String responseContent = this.getWxMpService().post(WxMpApiUrl.MemberCard.MEMBER_CARD_UPDATE_USER, GSON.toJson(updateUserMessage));
 
     JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
     return WxMpGsonBuilder.create().fromJson(tmpJsonElement,
@@ -243,7 +242,7 @@ public WxMpMemberCardUpdateResult updateUserMemberCard(WxMpMemberCardUpdateMessa
 
   @Override
   public MemberCardActivateUserFormResult setActivateUserForm(MemberCardActivateUserFormRequest userFormRequest) throws WxErrorException {
-    String responseContent = this.getWxMpService().post(MEMBER_CARD_ACTIVATE_USER_FORM, GSON.toJson(userFormRequest));
+    String responseContent = this.getWxMpService().post(WxMpApiUrl.MemberCard.MEMBER_CARD_ACTIVATE_USER_FORM, GSON.toJson(userFormRequest));
     return MemberCardActivateUserFormResult.fromJson(responseContent);
   }
 
@@ -252,7 +251,7 @@ public ActivatePluginParam getActivatePluginParam(String cardId, String outStr)
     JsonObject params = new JsonObject();
     params.addProperty("card_id", cardId);
     params.addProperty("outer_str", outStr);
-    String response = this.wxMpService.post(MEMBER_CARD_ACTIVATE_URL, GSON.toJson(params));
+    String response = this.wxMpService.post(WxMpApiUrl.MemberCard.MEMBER_CARD_ACTIVATE_URL, GSON.toJson(params));
     ActivatePluginParamResult result = GSON.fromJson(response, ActivatePluginParamResult.class);
     if (0 == result.getErrcode()) {
       String url = result.getUrl();
@@ -273,18 +272,16 @@ public ActivatePluginParam getActivatePluginParam(String cardId, String outStr)
 
   @Override
   public CardUpdateResult updateCardInfo(MemberCardUpdateRequest memberCardUpdateRequest) throws WxErrorException {
-    String response = this.wxMpService.post(MEMBER_CARD_UPDATE, GSON.toJson(memberCardUpdateRequest));
-    CardUpdateResult result = GSON.fromJson(response, CardUpdateResult.class);
-    return result;
+    String response = this.wxMpService.post(WxMpApiUrl.MemberCard.MEMBER_CARD_UPDATE, GSON.toJson(memberCardUpdateRequest));
+    return GSON.fromJson(response, CardUpdateResult.class);
   }
 
   @Override
   public WxMpMemberCardActivateTempInfoResult getActivateTempInfo(String activateTicket) throws WxErrorException {
     JsonObject params = new JsonObject();
     params.addProperty("activate_ticket", activateTicket);
-    String response = this.wxMpService.post(MEMBER_CARD_ACTIVATE_TEMP_INFO, GSON.toJson(params));
-    WxMpMemberCardActivateTempInfoResult result = GSON.fromJson(response, WxMpMemberCardActivateTempInfoResult.class);
-    return result;
+    String response = this.wxMpService.post(WxMpApiUrl.MemberCard.MEMBER_CARD_ACTIVATE_TEMP_INFO, GSON.toJson(params));
+    return GSON.fromJson(response, WxMpMemberCardActivateTempInfoResult.class);
   }
 
   private static String truncateUrlPage(String strURL) {
@@ -302,7 +299,7 @@ private static String truncateUrlPage(String strURL) {
     return strAllParam;
   }
 
-  public static Map parseRequestUrl(String url) {
+  private static Map parseRequestUrl(String url) {
     Map mapRequest = new HashMap<>(16);
 
     String[] arrSplit;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImpl.java
index e8dc84766b..2a42a0a590 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImpl.java
@@ -2,34 +2,34 @@
 
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.bean.menu.WxMenu;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.mp.api.WxMpMenuService;
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.bean.menu.WxMpGetSelfMenuInfoResult;
 import me.chanjar.weixin.mp.bean.menu.WxMpMenu;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import me.chanjar.weixin.mp.enums.WxMpApiUrl;
+
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Menu.*;
 
 /**
  * Created by Binary Wang on 2016/7/21.
+ *
+ * @author Binary Wang
  */
+@Slf4j
+@RequiredArgsConstructor
 public class WxMpMenuServiceImpl implements WxMpMenuService {
-  private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/menu";
-  private static Logger log = LoggerFactory.getLogger(WxMpMenuServiceImpl.class);
-
-  private WxMpService wxMpService;
-
-  public WxMpMenuServiceImpl(WxMpService wxMpService) {
-    this.wxMpService = wxMpService;
-  }
+  private final WxMpService wxMpService;
 
   @Override
   public String menuCreate(WxMenu menu) throws WxErrorException {
     String menuJson = menu.toJson();
-    String url = API_URL_PREFIX + "/create";
+    WxMpApiUrl.Menu url = MENU_CREATE;
     if (menu.getMatchRule() != null) {
-      url = API_URL_PREFIX + "/addconditional";
+      url = MENU_ADDCONDITIONAL;
     }
 
     log.debug("开始创建菜单:{}", menuJson);
@@ -48,9 +48,9 @@ public String menuCreate(WxMenu menu) throws WxErrorException {
   public String menuCreate(String json) throws WxErrorException {
     JsonParser jsonParser = new JsonParser();
     JsonObject jsonObject = jsonParser.parse(json).getAsJsonObject();
-    String url = API_URL_PREFIX + "/create";
+    WxMpApiUrl.Menu url = MENU_CREATE;
     if (jsonObject.get("matchrule") != null) {
-      url = API_URL_PREFIX + "/addconditional";
+      url = MENU_ADDCONDITIONAL;
     }
 
     String result = this.wxMpService.post(url, json);
@@ -63,25 +63,22 @@ public String menuCreate(String json) throws WxErrorException {
 
   @Override
   public void menuDelete() throws WxErrorException {
-    String url = API_URL_PREFIX + "/delete";
-    String result = this.wxMpService.get(url, null);
+    String result = this.wxMpService.get(MENU_DELETE, null);
     log.debug("删除菜单结果:{}", result);
   }
 
   @Override
   public void menuDelete(String menuId) throws WxErrorException {
-    String url = API_URL_PREFIX + "/delconditional";
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("menuid", menuId);
-    String result = this.wxMpService.post(url, jsonObject.toString());
+    String result = this.wxMpService.post(MENU_DELCONDITIONAL, jsonObject.toString());
     log.debug("根据MeunId({})删除个性化菜单结果:{}", menuId, result);
   }
 
   @Override
   public WxMpMenu menuGet() throws WxErrorException {
-    String url = API_URL_PREFIX + "/get";
     try {
-      String resultContent = this.wxMpService.get(url, null);
+      String resultContent = this.wxMpService.get(MENU_GET, null);
       return WxMpMenu.fromJson(resultContent);
     } catch (WxErrorException e) {
       // 46003 不存在的菜单数据
@@ -94,11 +91,10 @@ public WxMpMenu menuGet() throws WxErrorException {
 
   @Override
   public WxMenu menuTryMatch(String userid) throws WxErrorException {
-    String url = API_URL_PREFIX + "/trymatch";
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("user_id", userid);
     try {
-      String resultContent = this.wxMpService.post(url, jsonObject.toString());
+      String resultContent = this.wxMpService.post(MENU_TRYMATCH, jsonObject.toString());
       return WxMenu.fromJson(resultContent);
     } catch (WxErrorException e) {
       // 46003 不存在的菜单数据;46002 不存在的菜单版本
@@ -112,8 +108,7 @@ public WxMenu menuTryMatch(String userid) throws WxErrorException {
 
   @Override
   public WxMpGetSelfMenuInfoResult getSelfMenuInfo() throws WxErrorException {
-    String url = "https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info";
-    String resultContent = this.wxMpService.get(url, null);
+    String resultContent = this.wxMpService.get(GET_CURRENT_SELFMENU_INFO, null);
     return WxMpGetSelfMenuInfoResult.fromJson(resultContent);
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java
index 5783ce7991..da4171fbb4 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java
@@ -1,6 +1,7 @@
 package me.chanjar.weixin.mp.api.impl;
 
 import com.google.gson.JsonObject;
+import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.mp.api.WxMpQrcodeService;
@@ -14,16 +15,16 @@
 import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
 
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Qrcode.*;
+
 /**
  * Created by Binary Wang on 2016/7/21.
+ *
+ * @author Binary Wang
  */
+@RequiredArgsConstructor
 public class WxMpQrcodeServiceImpl implements WxMpQrcodeService {
-  private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/qrcode";
-  private WxMpService wxMpService;
-
-  public WxMpQrcodeServiceImpl(WxMpService wxMpService) {
-    this.wxMpService = wxMpService;
-  }
+  private final WxMpService wxMpService;
 
   @Override
   public WxMpQrCodeTicket qrCodeCreateTmpTicket(int sceneId, Integer expireSeconds) throws WxErrorException {
@@ -31,37 +32,20 @@ public WxMpQrCodeTicket qrCodeCreateTmpTicket(int sceneId, Integer expireSeconds
       throw new WxErrorException(WxError.builder().errorCode(-1).errorMsg("临时二维码场景值不能为0!").build());
     }
 
-    //expireSeconds 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒。
-    if (expireSeconds != null && expireSeconds > 2592000) {
-      throw new WxErrorException(WxError.builder().errorCode(-1)
-        .errorMsg("临时二维码有效时间最大不能超过2592000(即30天)!").build());
-    }
-
-    if (expireSeconds == null) {
-      expireSeconds = 30;
-    }
-
-    String url = API_URL_PREFIX + "/create";
-    JsonObject json = new JsonObject();
-    json.addProperty("action_name", "QR_SCENE");
-    json.addProperty("expire_seconds", expireSeconds);
-
-    JsonObject actionInfo = new JsonObject();
-    JsonObject scene = new JsonObject();
-    scene.addProperty("scene_id", sceneId);
-    actionInfo.add("scene", scene);
-    json.add("action_info", actionInfo);
-    String responseContent = this.wxMpService.post(url, json.toString());
-    return WxMpQrCodeTicket.fromJson(responseContent);
+    return this.createQrCode("QR_SCENE", null, sceneId, expireSeconds);
   }
 
-
   @Override
   public WxMpQrCodeTicket qrCodeCreateTmpTicket(String sceneStr, Integer expireSeconds) throws WxErrorException {
     if (StringUtils.isBlank(sceneStr)) {
       throw new WxErrorException(WxError.builder().errorCode(-1).errorMsg("临时二维码场景值不能为空!").build());
     }
 
+    return this.createQrCode("QR_STR_SCENE", sceneStr, null, expireSeconds);
+  }
+
+  private WxMpQrCodeTicket createQrCode(String actionName, String sceneStr, Integer sceneId, Integer expireSeconds)
+    throws WxErrorException {
     //expireSeconds 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒。
     if (expireSeconds != null && expireSeconds > 2592000) {
       throw new WxErrorException(WxError.builder().errorCode(-1)
@@ -72,21 +56,31 @@ public WxMpQrCodeTicket qrCodeCreateTmpTicket(String sceneStr, Integer expireSec
       expireSeconds = 30;
     }
 
-    String url = API_URL_PREFIX + "/create";
+    return this.getQrCodeTicket(actionName, sceneStr, sceneId, expireSeconds);
+  }
+
+  private WxMpQrCodeTicket getQrCodeTicket(String actionName, String sceneStr, Integer sceneId, Integer expireSeconds)
+    throws WxErrorException {
     JsonObject json = new JsonObject();
-    json.addProperty("action_name", "QR_STR_SCENE");
-    json.addProperty("expire_seconds", expireSeconds);
+    json.addProperty("action_name", actionName);
+    if (expireSeconds != null) {
+      json.addProperty("expire_seconds", expireSeconds);
+    }
 
     JsonObject actionInfo = new JsonObject();
     JsonObject scene = new JsonObject();
-    scene.addProperty("scene_str", sceneStr);
+    if (sceneStr != null) {
+      scene.addProperty("scene_str", sceneStr);
+    } else if (sceneId != null) {
+      scene.addProperty("scene_id", sceneId);
+    }
+
     actionInfo.add("scene", scene);
     json.add("action_info", actionInfo);
-    String responseContent = this.wxMpService.post(url, json.toString());
+    String responseContent = this.wxMpService.post(QRCODE_CREATE, json.toString());
     return WxMpQrCodeTicket.fromJson(responseContent);
   }
 
-
   @Override
   public WxMpQrCodeTicket qrCodeCreateLastTicket(int sceneId) throws WxErrorException {
     if (sceneId < 1 || sceneId > 100000) {
@@ -95,44 +89,23 @@ public WxMpQrCodeTicket qrCodeCreateLastTicket(int sceneId) throws WxErrorExcept
         .build());
     }
 
-    String url = API_URL_PREFIX + "/create";
-    JsonObject json = new JsonObject();
-    json.addProperty("action_name", "QR_LIMIT_SCENE");
-    JsonObject actionInfo = new JsonObject();
-    JsonObject scene = new JsonObject();
-    scene.addProperty("scene_id", sceneId);
-    actionInfo.add("scene", scene);
-    json.add("action_info", actionInfo);
-    String responseContent = this.wxMpService.post(url, json.toString());
-    return WxMpQrCodeTicket.fromJson(responseContent);
+    return this.getQrCodeTicket("QR_LIMIT_SCENE", null, sceneId, null);
   }
 
   @Override
   public WxMpQrCodeTicket qrCodeCreateLastTicket(String sceneStr) throws WxErrorException {
-    String url = API_URL_PREFIX + "/create";
-    JsonObject json = new JsonObject();
-    json.addProperty("action_name", "QR_LIMIT_STR_SCENE");
-    JsonObject actionInfo = new JsonObject();
-    JsonObject scene = new JsonObject();
-    scene.addProperty("scene_str", sceneStr);
-    actionInfo.add("scene", scene);
-    json.add("action_info", actionInfo);
-    String responseContent = this.wxMpService.post(url, json.toString());
-    return WxMpQrCodeTicket.fromJson(responseContent);
+    return this.getQrCodeTicket("QR_LIMIT_STR_SCENE", sceneStr, null, null);
   }
 
   @Override
   public File qrCodePicture(WxMpQrCodeTicket ticket) throws WxErrorException {
-    String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode";
-    return this.wxMpService.execute(QrCodeRequestExecutor.create(this.wxMpService.getRequestHttp()), url, ticket);
+    return this.wxMpService.execute(QrCodeRequestExecutor.create(this.wxMpService.getRequestHttp()), SHOW_QRCODE, ticket);
   }
 
   @Override
   public String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErrorException {
-    String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s";
     try {
-      String resultUrl = String.format(url,
-        URLEncoder.encode(ticket, StandardCharsets.UTF_8.name()));
+      String resultUrl = String.format(SHOW_QRCODE_WITH_TICKET.getUrl(), URLEncoder.encode(ticket, StandardCharsets.UTF_8.name()));
       if (needShortUrl) {
         return this.wxMpService.shortUrl(resultUrl);
       }
@@ -145,7 +118,7 @@ public String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErr
 
   @Override
   public String qrCodePictureUrl(String ticket) throws WxErrorException {
-    return qrCodePictureUrl(ticket, false);
+    return this.qrCodePictureUrl(ticket, false);
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java
index 10e2a5b78f..0c00793a0c 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java
@@ -8,7 +8,7 @@
 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.mp.api.WxMpService;
+import me.chanjar.weixin.mp.enums.WxMpApiUrl;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
 import org.apache.http.client.methods.CloseableHttpResponse;
@@ -19,8 +19,12 @@
 import java.io.IOException;
 import java.util.concurrent.locks.Lock;
 
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.*;
+
 /**
  * apache http client方式实现.
+ *
+ * @author someone
  */
 public class WxMpServiceHttpClientImpl extends BaseWxMpServiceImpl {
   private CloseableHttpClient httpClient;
@@ -70,7 +74,7 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
     Lock lock = this.getWxMpConfigStorage().getAccessTokenLock();
     lock.lock();
     try {
-      String url = String.format(WxMpService.GET_ACCESS_TOKEN_URL,
+      String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(),
         this.getWxMpConfigStorage().getAppId(), this.getWxMpConfigStorage().getSecret());
       try {
         HttpGet httpGet = new HttpGet(url);
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java
index c00cd43234..9b78f04cad 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java
@@ -8,12 +8,15 @@
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.HttpType;
 import me.chanjar.weixin.mp.api.WxMpConfigStorage;
-import me.chanjar.weixin.mp.api.WxMpService;
 
 import java.util.concurrent.locks.Lock;
 
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.GET_ACCESS_TOKEN_URL;
+
 /**
- * jodd-http方式实现
+ * jodd-http方式实现.
+ *
+ * @author someone
  */
 public class WxMpServiceJoddHttpImpl extends BaseWxMpServiceImpl {
   private HttpConnectionProvider httpClient;
@@ -55,7 +58,7 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
     Lock lock = this.getWxMpConfigStorage().getAccessTokenLock();
     lock.lock();
     try {
-      String url = String.format(WxMpService.GET_ACCESS_TOKEN_URL,
+      String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(),
         this.getWxMpConfigStorage().getAppId(), this.getWxMpConfigStorage().getSecret());
 
       HttpRequest request = HttpRequest.get(url);
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java
index 89771250ef..f166d93c7f 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java
@@ -7,14 +7,18 @@
 import me.chanjar.weixin.common.util.http.HttpType;
 import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
 import me.chanjar.weixin.mp.api.WxMpConfigStorage;
-import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.enums.WxMpApiUrl;
 import okhttp3.*;
 
 import java.io.IOException;
 import java.util.concurrent.locks.Lock;
 
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.*;
+
 /**
- * okhttp实现
+ * okhttp实现.
+ *
+ * @author someone
  */
 public class WxMpServiceOkHttpImpl extends BaseWxMpServiceImpl {
   private OkHttpClient httpClient;
@@ -44,7 +48,7 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
     Lock lock = this.getWxMpConfigStorage().getAccessTokenLock();
     lock.lock();
     try {
-      String url = String.format(WxMpService.GET_ACCESS_TOKEN_URL,
+      String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(),
         this.getWxMpConfigStorage().getAppId(), this.getWxMpConfigStorage().getSecret());
 
       Request request = new Request.Builder().url(url).get().build();
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpShakeServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpShakeServiceImpl.java
index 6f6beda5ab..95efcb7f5c 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpShakeServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpShakeServiceImpl.java
@@ -1,5 +1,6 @@
 package me.chanjar.weixin.mp.api.impl;
 
+import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
@@ -9,59 +10,45 @@
 import me.chanjar.weixin.mp.bean.WxMpShakeQuery;
 import me.chanjar.weixin.mp.bean.shake.*;
 
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.ShakeAround.*;
+
 /**
  * Created by rememberber on 2017/6/5.
  *
  * @author rememberber
  */
+@RequiredArgsConstructor
 public class WxMpShakeServiceImpl implements WxMpShakeService {
+  private final WxMpService wxMpService;
 
-  private WxMpService wxMpService;
-
-  public WxMpShakeServiceImpl(WxMpService wxMpService) {
-    this.wxMpService = wxMpService;
-  }
-
-  /**
-   * 
-   * 获取设备及用户信息
- * 获取设备信息,包括UUID、major、minor,以及距离、openID等信息。 - * 详情请见: https://mp.weixin.qq.com/wiki?action=doc&id=mp1443447963 - * http请求方式: POST(请使用https协议) - * 接口地址:https://api.weixin.qq.com/shakearound/user/getshakeinfo?access_token=ACCESS_TOKE - *
- * - * @param wxMpShakeQuery 查询参数 - */ @Override public WxMpShakeInfoResult getShakeInfo(WxMpShakeQuery wxMpShakeQuery) throws WxErrorException { - String url = "https://api.weixin.qq.com/shakearound/user/getshakeinfo"; String postData = wxMpShakeQuery.toJsonString(); - String responseContent = this.wxMpService.post(url, postData); + String responseContent = this.wxMpService.post(SHAKEAROUND_USER_GETSHAKEINFO, postData); return WxMpShakeInfoResult.fromJson(responseContent); } @Override - public WxMpShakeAroundPageAddResult pageAdd(WxMpShakeAroundPageAddQuery shakeAroundPageAddQuery) throws WxErrorException { - String url = "https://api.weixin.qq.com/shakearound/page/add"; + public WxMpShakeAroundPageAddResult pageAdd(WxMpShakeAroundPageAddQuery shakeAroundPageAddQuery) + throws WxErrorException { String postData = shakeAroundPageAddQuery.toJsonString(); - String responseContent = this.wxMpService.post(url, postData); + String responseContent = this.wxMpService.post(SHAKEAROUND_PAGE_ADD, postData); return WxMpShakeAroundPageAddResult.fromJson(responseContent); } @Override - public WxError deviceBindPageQuery(WxMpShakeAroundDeviceBindPageQuery shakeAroundDeviceBindPageQuery) throws WxErrorException { - String url = "https://api.weixin.qq.com/shakearound/device/bindpage"; + public WxError deviceBindPageQuery(WxMpShakeAroundDeviceBindPageQuery shakeAroundDeviceBindPageQuery) + throws WxErrorException { String postData = shakeAroundDeviceBindPageQuery.toJsonString(); - String responseContent = this.wxMpService.post(url, postData); + String responseContent = this.wxMpService.post(SHAKEAROUND_DEVICE_BINDPAGE, postData); return WxError.fromJson(responseContent, WxType.MP); } @Override - public WxMpShakeAroundRelationSearchResult relationSearch(WxMpShakeAroundRelationSearchQuery shakeAroundRelationSearchQuery) throws WxErrorException { - String url = "https://api.weixin.qq.com/shakearound/relation/search"; - String postData = shakeAroundRelationSearchQuery.toJsonString(); - String responseContent = this.wxMpService.post(url, postData); + public WxMpShakeAroundRelationSearchResult relationSearch(WxMpShakeAroundRelationSearchQuery searchQuery) + throws WxErrorException { + String postData = searchQuery.toJsonString(); + String responseContent = this.wxMpService.post(SHAKEAROUND_RELATION_SEARCH, postData); return WxMpShakeAroundRelationSearchResult.fromJson(responseContent); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImpl.java index 402102064c..913816595c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImpl.java @@ -3,6 +3,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.WxType; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; @@ -12,6 +13,7 @@ import me.chanjar.weixin.mp.bean.store.WxMpStoreBaseInfo; import me.chanjar.weixin.mp.bean.store.WxMpStoreInfo; import me.chanjar.weixin.mp.bean.store.WxMpStoreListResult; +import me.chanjar.weixin.mp.enums.WxMpApiUrl; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; import java.util.List; @@ -21,18 +23,15 @@ * * @author binarywang (https://github.com/binarywang) */ +@RequiredArgsConstructor public class WxMpStoreServiceImpl implements WxMpStoreService { - private WxMpService wxMpService; - - public WxMpStoreServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } + private final WxMpService wxMpService; @Override public void add(WxMpStoreBaseInfo request) throws WxErrorException { BeanUtils.checkRequiredFields(request); - String response = this.wxMpService.post(POI_ADD_URL, request.toJson()); + String response = this.wxMpService.post(WxMpApiUrl.Store.POI_ADD_URL, request.toJson()); WxError wxError = WxError.fromJson(response, WxType.MP); if (wxError.getErrorCode() != 0) { throw new WxErrorException(wxError); @@ -43,7 +42,7 @@ public void add(WxMpStoreBaseInfo request) throws WxErrorException { public WxMpStoreBaseInfo get(String poiId) throws WxErrorException { JsonObject paramObject = new JsonObject(); paramObject.addProperty("poi_id", poiId); - String response = this.wxMpService.post(POI_GET_URL, paramObject.toString()); + String response = this.wxMpService.post(WxMpApiUrl.Store.POI_GET_URL, paramObject.toString()); WxError wxError = WxError.fromJson(response, WxType.MP); if (wxError.getErrorCode() != 0) { throw new WxErrorException(wxError); @@ -56,7 +55,7 @@ public WxMpStoreBaseInfo get(String poiId) throws WxErrorException { public void delete(String poiId) throws WxErrorException { JsonObject paramObject = new JsonObject(); paramObject.addProperty("poi_id", poiId); - String response = this.wxMpService.post(POI_DEL_URL, paramObject.toString()); + String response = this.wxMpService.post(WxMpApiUrl.Store.POI_DEL_URL, paramObject.toString()); WxError wxError = WxError.fromJson(response, WxType.MP); if (wxError.getErrorCode() != 0) { throw new WxErrorException(wxError); @@ -69,7 +68,7 @@ public WxMpStoreListResult list(int begin, int limit) JsonObject params = new JsonObject(); params.addProperty("begin", begin); params.addProperty("limit", limit); - String response = this.wxMpService.post(POI_LIST_URL, params.toString()); + String response = this.wxMpService.post(WxMpApiUrl.Store.POI_LIST_URL, params.toString()); WxError wxError = WxError.fromJson(response, WxType.MP); if (wxError.getErrorCode() != 0) { @@ -102,7 +101,7 @@ public List listAll() throws WxErrorException { @Override public void update(WxMpStoreBaseInfo request) throws WxErrorException { - String response = this.wxMpService.post(POI_UPDATE_URL, request.toJson()); + String response = this.wxMpService.post(WxMpApiUrl.Store.POI_UPDATE_URL, request.toJson()); WxError wxError = WxError.fromJson(response, WxType.MP); if (wxError.getErrorCode() != 0) { throw new WxErrorException(wxError); @@ -111,7 +110,7 @@ public void update(WxMpStoreBaseInfo request) throws WxErrorException { @Override public List listCategories() throws WxErrorException { - String response = this.wxMpService.get(POI_GET_WX_CATEGORY_URL, null); + String response = this.wxMpService.get(WxMpApiUrl.Store.POI_GET_WX_CATEGORY_URL, null); WxError wxError = WxError.fromJson(response, WxType.MP); if (wxError.getErrorCode() != 0) { throw new WxErrorException(wxError); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpSubscribeMsgServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpSubscribeMsgServiceImpl.java index fe1cfb306c..d68342869e 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpSubscribeMsgServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpSubscribeMsgServiceImpl.java @@ -1,32 +1,30 @@ package me.chanjar.weixin.mp.api.impl; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.URIUtil; import me.chanjar.weixin.mp.api.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpSubscribeMsgService; import me.chanjar.weixin.mp.bean.subscribe.WxMpSubscribeMessage; +import me.chanjar.weixin.mp.enums.WxMpApiUrl; + +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.SubscribeMsg.*; /** + * 一次性订阅消息接口. + * * @author Mklaus * @date 2018-01-22 上午11:19 */ +@RequiredArgsConstructor public class WxMpSubscribeMsgServiceImpl implements WxMpSubscribeMsgService { - private static final String SUBSCRIBE_MESSAGE_AUTHORIZE_URL = - "https://mp.weixin.qq.com/mp/subscribemsg?action=get_confirm&appid=%s&scene=%d&template_id=%s&redirect_url=%s&reserved=%s#wechat_redirect"; - private static final String SEND_MESSAGE_URL = "https://api.weixin.qq.com/cgi-bin/message/template/subscribe"; - - - private WxMpService wxMpService; - - public WxMpSubscribeMsgServiceImpl(WxMpService wxMpService) { - this.wxMpService = wxMpService; - } + private final WxMpService wxMpService; @Override public String subscribeMsgAuthorizationUrl(String redirectURI, int scene, String reserved) { WxMpConfigStorage storage = this.wxMpService.getWxMpConfigStorage(); - return String.format(SUBSCRIBE_MESSAGE_AUTHORIZE_URL, + return String.format(SUBSCRIBE_MESSAGE_AUTHORIZE_URL.getUrl(), storage.getAppId(), scene, storage.getTemplateId(), URIUtil.encodeURIComponent(redirectURI), reserved); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpTemplateMsgServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpTemplateMsgServiceImpl.java index 472cd0fe8c..4cab8d71eb 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpTemplateMsgServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpTemplateMsgServiceImpl.java @@ -2,6 +2,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.WxType; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; @@ -10,9 +11,12 @@ import me.chanjar.weixin.mp.bean.template.WxMpTemplate; import me.chanjar.weixin.mp.bean.template.WxMpTemplateIndustry; import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage; +import me.chanjar.weixin.mp.enums.WxMpApiUrl; import java.util.List; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.TemplateMsg.*; + /** *
  * Created by Binary Wang on 2016-10-14.
@@ -20,20 +24,15 @@
  *
  * @author Binary Wang
  */
+@RequiredArgsConstructor
 public class WxMpTemplateMsgServiceImpl implements WxMpTemplateMsgService {
-  public static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/template";
   private static final JsonParser JSON_PARSER = new JsonParser();
 
-  private WxMpService wxMpService;
-
-  public WxMpTemplateMsgServiceImpl(WxMpService wxMpService) {
-    this.wxMpService = wxMpService;
-  }
+  private final WxMpService wxMpService;
 
   @Override
   public String sendTemplateMsg(WxMpTemplateMessage templateMessage) throws WxErrorException {
-    String url = "https://api.weixin.qq.com/cgi-bin/message/template/send";
-    String responseContent = this.wxMpService.post(url, templateMessage.toJson());
+    String responseContent = this.wxMpService.post(MESSAGE_TEMPLATE_SEND, templateMessage.toJson());
     final JsonObject jsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject();
     if (jsonObject.get("errcode").getAsInt() == 0) {
       return jsonObject.get("msgid").getAsString();
@@ -48,24 +47,21 @@ public boolean setIndustry(WxMpTemplateIndustry wxMpIndustry) throws WxErrorExce
       throw new IllegalArgumentException("行业Id不能为空,请核实");
     }
 
-    String url = API_URL_PREFIX + "/api_set_industry";
-    this.wxMpService.post(url, wxMpIndustry.toJson());
+    this.wxMpService.post(TEMPLATE_API_SET_INDUSTRY, wxMpIndustry.toJson());
     return true;
   }
 
   @Override
   public WxMpTemplateIndustry getIndustry() throws WxErrorException {
-    String url = API_URL_PREFIX + "/get_industry";
-    String responseContent = this.wxMpService.get(url, null);
+    String responseContent = this.wxMpService.get(TEMPLATE_GET_INDUSTRY, null);
     return WxMpTemplateIndustry.fromJson(responseContent);
   }
 
   @Override
   public String addTemplate(String shortTemplateId) throws WxErrorException {
-    String url = API_URL_PREFIX + "/api_add_template";
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("template_id_short", shortTemplateId);
-    String responseContent = this.wxMpService.post(url, jsonObject.toString());
+    String responseContent = this.wxMpService.post(TEMPLATE_API_ADD_TEMPLATE, jsonObject.toString());
     final JsonObject result = JSON_PARSER.parse(responseContent).getAsJsonObject();
     if (result.get("errcode").getAsInt() == 0) {
       return result.get("template_id").getAsString();
@@ -76,16 +72,14 @@ public String addTemplate(String shortTemplateId) throws WxErrorException {
 
   @Override
   public List getAllPrivateTemplate() throws WxErrorException {
-    String url = API_URL_PREFIX + "/get_all_private_template";
-    return WxMpTemplate.fromJson(this.wxMpService.get(url, null));
+    return WxMpTemplate.fromJson(this.wxMpService.get(TEMPLATE_GET_ALL_PRIVATE_TEMPLATE, null));
   }
 
   @Override
   public boolean delPrivateTemplate(String templateId) throws WxErrorException {
-    String url = API_URL_PREFIX + "/del_private_template";
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("template_id", templateId);
-    String responseContent = this.wxMpService.post(url, jsonObject.toString());
+    String responseContent = this.wxMpService.post(TEMPLATE_DEL_PRIVATE_TEMPLATE, jsonObject.toString());
     WxError error = WxError.fromJson(responseContent, WxType.MP);
     if (error.getErrorCode() == 0) {
       return true;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java
index a6ba958eb5..cd7ac541ae 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserBlacklistServiceImpl.java
@@ -1,43 +1,42 @@
 package me.chanjar.weixin.mp.api.impl;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
 import com.google.gson.JsonObject;
+import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.api.WxMpUserBlacklistService;
 import me.chanjar.weixin.mp.bean.result.WxMpUserBlacklistGetResult;
+import me.chanjar.weixin.mp.enums.WxMpApiUrl;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.UserBlacklist.*;
+
 /**
  * @author miller
  */
+@RequiredArgsConstructor
 public class WxMpUserBlacklistServiceImpl implements WxMpUserBlacklistService {
-  private static final String API_BLACKLIST_PREFIX = "https://api.weixin.qq.com/cgi-bin/tags/members";
-  private WxMpService wxMpService;
-
-  public WxMpUserBlacklistServiceImpl(WxMpService wxMpService) {
-    this.wxMpService = wxMpService;
-  }
+  private final WxMpService wxMpService;
 
   @Override
   public WxMpUserBlacklistGetResult getBlacklist(String nextOpenid) throws WxErrorException {
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("begin_openid", nextOpenid);
-    String url = API_BLACKLIST_PREFIX + "/getblacklist";
-    String responseContent = this.wxMpService.execute(SimplePostRequestExecutor.create(this.wxMpService.getRequestHttp()), url, jsonObject.toString());
+    String responseContent = this.wxMpService.execute(SimplePostRequestExecutor.create(this.wxMpService.getRequestHttp()),
+      GETBLACKLIST, jsonObject.toString());
     return WxMpUserBlacklistGetResult.fromJson(responseContent);
   }
 
   @Override
   public void pushToBlacklist(List openidList) throws WxErrorException {
-    Map map = new HashMap<>();
+    Map map = new HashMap<>(2);
     map.put("openid_list", openidList);
-    String url = API_BLACKLIST_PREFIX + "/batchblacklist";
-    this.wxMpService.execute(SimplePostRequestExecutor.create(this.wxMpService.getRequestHttp()), url,
+    this.wxMpService.execute(SimplePostRequestExecutor.create(this.wxMpService.getRequestHttp()), BATCHBLACKLIST,
       WxMpGsonBuilder.create().toJson(map));
   }
 
@@ -45,7 +44,7 @@ public void pushToBlacklist(List openidList) throws WxErrorException {
   public void pullFromBlacklist(List openidList) throws WxErrorException {
     Map map = new HashMap<>(2);
     map.put("openid_list", openidList);
-    String url = API_BLACKLIST_PREFIX + "/batchunblacklist";
-    this.wxMpService.execute(SimplePostRequestExecutor.create(this.wxMpService.getRequestHttp()), url, WxMpGsonBuilder.create().toJson(map));
+    this.wxMpService.execute(SimplePostRequestExecutor.create(this.wxMpService.getRequestHttp()), BATCHUNBLACKLIST,
+      WxMpGsonBuilder.create().toJson(map));
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImpl.java
index d8c8943d36..0c77a93ffc 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImpl.java
@@ -1,11 +1,7 @@
 package me.chanjar.weixin.mp.api.impl;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import com.google.gson.JsonArray;
 import com.google.gson.JsonObject;
+import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.api.WxMpUserService;
@@ -13,19 +9,23 @@
 import me.chanjar.weixin.mp.bean.result.WxMpChangeOpenid;
 import me.chanjar.weixin.mp.bean.result.WxMpUser;
 import me.chanjar.weixin.mp.bean.result.WxMpUserList;
+import me.chanjar.weixin.mp.enums.WxMpApiUrl;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.User.*;
+
 /**
  * Created by Binary Wang on 2016/7/21.
  *
  * @author BinaryWang
  */
+@RequiredArgsConstructor
 public class WxMpUserServiceImpl implements WxMpUserService {
-  private WxMpService wxMpService;
-
-  public WxMpUserServiceImpl(WxMpService wxMpService) {
-    this.wxMpService = wxMpService;
-  }
+  private final WxMpService wxMpService;
 
   @Override
   public void userUpdateRemark(String openid, String remark) throws WxErrorException {
@@ -43,21 +43,19 @@ public WxMpUser userInfo(String openid) throws WxErrorException {
   @Override
   public WxMpUser userInfo(String openid, String lang) throws WxErrorException {
     lang = lang == null ? "zh_CN" : lang;
-    String responseContent = this.wxMpService.get(USER_INFO_URL,
-      "openid=" + openid + "&lang=" + lang);
+    String responseContent = this.wxMpService.get(USER_INFO_URL, "openid=" + openid + "&lang=" + lang);
     return WxMpUser.fromJson(responseContent);
   }
 
   @Override
   public WxMpUserList userList(String nextOpenid) throws WxErrorException {
-    String responseContent = this.wxMpService.get(USER_GET_URL,
-      nextOpenid == null ? null : "next_openid=" + nextOpenid);
+    String responseContent = this.wxMpService.get(USER_GET_URL, nextOpenid == null ? null : "next_openid=" + nextOpenid);
     return WxMpUserList.fromJson(responseContent);
   }
 
   @Override
   public List changeOpenid(String fromAppid, List openidList) throws WxErrorException {
-    Map map = new HashMap<>();
+    Map map = new HashMap<>(2);
     map.put("from_appid", fromAppid);
     map.put("openid_list", openidList);
     String responseContent = this.wxMpService.post(USER_CHANGE_OPENID_URL, WxMpGsonBuilder.create().toJson(map));
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserTagServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserTagServiceImpl.java
index 6a37741b84..bf4696e497 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserTagServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserTagServiceImpl.java
@@ -4,6 +4,7 @@
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
 import com.google.gson.reflect.TypeToken;
+import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
@@ -16,51 +17,43 @@
 
 import java.util.List;
 
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.UserTag.*;
+
 /**
  * Created by Binary Wang on 2016/9/2.
  *
  * @author Binary Wang
  */
+@RequiredArgsConstructor
 public class WxMpUserTagServiceImpl implements WxMpUserTagService {
-  private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/tags";
-
-  private WxMpService wxMpService;
-
-  public WxMpUserTagServiceImpl(WxMpService wxMpService) {
-    this.wxMpService = wxMpService;
-  }
+  private final WxMpService wxMpService;
 
   @Override
   public WxUserTag tagCreate(String name) throws WxErrorException {
-    String url = API_URL_PREFIX + "/create";
     JsonObject json = new JsonObject();
     JsonObject tagJson = new JsonObject();
     tagJson.addProperty("name", name);
     json.add("tag", tagJson);
 
-    String responseContent = this.wxMpService.post(url, json.toString());
+    String responseContent = this.wxMpService.post(TAGS_CREATE, json.toString());
     return WxUserTag.fromJson(responseContent);
   }
 
   @Override
   public List tagGet() throws WxErrorException {
-    String url = API_URL_PREFIX + "/get";
-
-    String responseContent = this.wxMpService.get(url, null);
+    String responseContent = this.wxMpService.get(TAGS_GET, null);
     return WxUserTag.listFromJson(responseContent);
   }
 
   @Override
   public Boolean tagUpdate(Long id, String name) throws WxErrorException {
-    String url = API_URL_PREFIX + "/update";
-
     JsonObject json = new JsonObject();
     JsonObject tagJson = new JsonObject();
     tagJson.addProperty("id", id);
     tagJson.addProperty("name", name);
     json.add("tag", tagJson);
 
-    String responseContent = this.wxMpService.post(url, json.toString());
+    String responseContent = this.wxMpService.post(TAGS_UPDATE, json.toString());
     WxError wxError = WxError.fromJson(responseContent, WxType.MP);
     if (wxError.getErrorCode() == 0) {
       return true;
@@ -71,14 +64,12 @@ public Boolean tagUpdate(Long id, String name) throws WxErrorException {
 
   @Override
   public Boolean tagDelete(Long id) throws WxErrorException {
-    String url = API_URL_PREFIX + "/delete";
-
     JsonObject json = new JsonObject();
     JsonObject tagJson = new JsonObject();
     tagJson.addProperty("id", id);
     json.add("tag", tagJson);
 
-    String responseContent = this.wxMpService.post(url, json.toString());
+    String responseContent = this.wxMpService.post(TAGS_DELETE, json.toString());
     WxError wxError = WxError.fromJson(responseContent, WxType.MP);
     if (wxError.getErrorCode() == 0) {
       return true;
@@ -88,23 +79,17 @@ public Boolean tagDelete(Long id) throws WxErrorException {
   }
 
   @Override
-  public WxTagListUser tagListUser(Long tagId, String nextOpenid)
-    throws WxErrorException {
-    String url = "https://api.weixin.qq.com/cgi-bin/user/tag/get";
-
+  public WxTagListUser tagListUser(Long tagId, String nextOpenid) throws WxErrorException {
     JsonObject json = new JsonObject();
     json.addProperty("tagid", tagId);
     json.addProperty("next_openid", StringUtils.trimToEmpty(nextOpenid));
 
-    String responseContent = this.wxMpService.post(url, json.toString());
+    String responseContent = this.wxMpService.post(TAG_GET, json.toString());
     return WxTagListUser.fromJson(responseContent);
   }
 
   @Override
-  public boolean batchTagging(Long tagId, String[] openids)
-    throws WxErrorException {
-    String url = API_URL_PREFIX + "/members/batchtagging";
-
+  public boolean batchTagging(Long tagId, String[] openids) throws WxErrorException {
     JsonObject json = new JsonObject();
     json.addProperty("tagid", tagId);
     JsonArray openidArrayJson = new JsonArray();
@@ -113,7 +98,7 @@ public boolean batchTagging(Long tagId, String[] openids)
     }
     json.add("openid_list", openidArrayJson);
 
-    String responseContent = this.wxMpService.post(url, json.toString());
+    String responseContent = this.wxMpService.post(TAGS_MEMBERS_BATCHTAGGING, json.toString());
     WxError wxError = WxError.fromJson(responseContent, WxType.MP);
     if (wxError.getErrorCode() == 0) {
       return true;
@@ -123,10 +108,7 @@ public boolean batchTagging(Long tagId, String[] openids)
   }
 
   @Override
-  public boolean batchUntagging(Long tagId, String[] openids)
-    throws WxErrorException {
-    String url = API_URL_PREFIX + "/members/batchuntagging";
-
+  public boolean batchUntagging(Long tagId, String[] openids) throws WxErrorException {
     JsonObject json = new JsonObject();
     json.addProperty("tagid", tagId);
     JsonArray openidArrayJson = new JsonArray();
@@ -135,7 +117,7 @@ public boolean batchUntagging(Long tagId, String[] openids)
     }
     json.add("openid_list", openidArrayJson);
 
-    String responseContent = this.wxMpService.post(url, json.toString());
+    String responseContent = this.wxMpService.post(TAGS_MEMBERS_BATCHUNTAGGING, json.toString());
     WxError wxError = WxError.fromJson(responseContent, WxType.MP);
     if (wxError.getErrorCode() == 0) {
       return true;
@@ -146,12 +128,10 @@ public boolean batchUntagging(Long tagId, String[] openids)
 
   @Override
   public List userTagList(String openid) throws WxErrorException {
-    String url = API_URL_PREFIX + "/getidlist";
-
     JsonObject json = new JsonObject();
     json.addProperty("openid", openid);
 
-    String responseContent = this.wxMpService.post(url, json.toString());
+    String responseContent = this.wxMpService.post(TAGS_GETIDLIST, json.toString());
 
     return WxMpGsonBuilder.create().fromJson(
       new JsonParser().parse(responseContent).getAsJsonObject().get("tagid_list"),
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java
index f87c784b89..357ae58014 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java
@@ -1,10 +1,14 @@
 package me.chanjar.weixin.mp.api.impl;
 
 import com.google.gson.JsonObject;
+import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.api.WxMpWifiService;
 import me.chanjar.weixin.mp.bean.wifi.WxMpWifiShopListResult;
+import me.chanjar.weixin.mp.enums.WxMpApiUrl;
+
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Wifi.*;
 
 /**
  * 
@@ -13,19 +17,16 @@
  *
  * @author Binary Wang
  */
+@RequiredArgsConstructor
 public class WxMpWifiServiceImpl implements WxMpWifiService {
-  private WxMpService wxMpService;
-
-  public WxMpWifiServiceImpl(WxMpService wxMpService) {
-    this.wxMpService = wxMpService;
-  }
+  private final WxMpService wxMpService;
 
   @Override
   public WxMpWifiShopListResult listShop(int pageIndex, int pageSize) throws WxErrorException {
     JsonObject json = new JsonObject();
     json.addProperty("pageindex", pageIndex);
     json.addProperty("pagesize", pageSize);
-    final String result = this.wxMpService.post("https://api.weixin.qq.com/bizwifi/shop/list", json.toString());
+    final String result = this.wxMpService.post(BIZWIFI_SHOP_LIST, json.toString());
     return WxMpWifiShopListResult.fromJson(result);
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Card.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Card.java
index c97f88f2fc..506101089c 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Card.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/Card.java
@@ -9,11 +9,10 @@
 /**
  * .
  * @author leeis
- * @Date 2018/12/29
+ * @date 2018/12/29
  */
 @Data
 public class Card implements Serializable {
-
   private static final long serialVersionUID = -3697110761983756780L;
 
   /**
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java
new file mode 100644
index 0000000000..2ab5fd7016
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java
@@ -0,0 +1,837 @@
+package me.chanjar.weixin.mp.enums;
+
+import lombok.AllArgsConstructor;
+
+/**
+ * 
+ *  公众号接口api地址
+ *  Created by BinaryWang on 2019-06-03.
+ * 
+ * + * @author Binary Wang + */ +public interface WxMpApiUrl { + String WX_API_BASE_URL = "https://api.weixin.qq.com"; + String WX_MP_BASE_URL = "https://mp.weixin.qq.com"; + String WX_OPEN_BASE_URL = "https://open.weixin.qq.com"; + + /** + * 得到api完整地址. + * + * @return api地址 + */ + String getUrl(); + + @AllArgsConstructor + enum Device implements WxMpApiUrl { + /** + * get_bind_device. + */ + DEVICE_GET_BIND_DEVICE(WX_API_BASE_URL, "/device/get_bind_device"), + /** + * get_openid. + */ + DEVICE_GET_OPENID(WX_API_BASE_URL, "/device/get_openid"), + /** + * compel_unbind. + */ + DEVICE_COMPEL_UNBIND(WX_API_BASE_URL, "/device/compel_unbind?"), + /** + * unbind. + */ + DEVICE_UNBIND(WX_API_BASE_URL, "/device/unbind?"), + /** + * compel_bind. + */ + DEVICE_COMPEL_BIND(WX_API_BASE_URL, "/device/compel_bind"), + /** + * bind. + */ + DEVICE_BIND(WX_API_BASE_URL, "/device/bind"), + /** + * authorize_device. + */ + DEVICE_AUTHORIZE_DEVICE(WX_API_BASE_URL, "/device/authorize_device"), + /** + * getqrcode. + */ + DEVICE_GETQRCODE(WX_API_BASE_URL, "/device/getqrcode"), + /** + * transmsg. + */ + DEVICE_TRANSMSG(WX_API_BASE_URL, "/device/transmsg"); + + private String prefix; + private String path; + + @Override + public String getUrl() { + return this.prefix + this.path; + } + } + + + @AllArgsConstructor + enum Other implements WxMpApiUrl { + /** + * 获取access_token. + */ + GET_ACCESS_TOKEN_URL(WX_API_BASE_URL, "/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"), + /** + * 获得各种类型的ticket. + */ + GET_TICKET_URL(WX_API_BASE_URL, "/cgi-bin/ticket/getticket?type="), + /** + * 长链接转短链接接口. + */ + SHORTURL_API_URL(WX_API_BASE_URL, "/cgi-bin/shorturl"), + /** + * 语义查询接口. + */ + SEMANTIC_SEMPROXY_SEARCH_URL(WX_API_BASE_URL, "/semantic/semproxy/search"), + /** + * 用code换取oauth2的access token. + */ + OAUTH2_ACCESS_TOKEN_URL(WX_API_BASE_URL, "/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code"), + /** + * 刷新oauth2的access token. + */ + OAUTH2_REFRESH_TOKEN_URL(WX_API_BASE_URL, "/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s"), + /** + * 用oauth2获取用户信息. + */ + OAUTH2_USERINFO_URL(WX_API_BASE_URL, "/sns/userinfo?access_token=%s&openid=%s&lang=%s"), + /** + * 验证oauth2的access token是否有效. + */ + OAUTH2_VALIDATE_TOKEN_URL(WX_API_BASE_URL, "/sns/auth?access_token=%s&openid=%s"), + /** + * 获取微信服务器IP地址. + */ + GET_CALLBACK_IP_URL(WX_API_BASE_URL, "/cgi-bin/getcallbackip"), + /** + * 第三方使用网站应用授权登录的url. + */ + QRCONNECT_URL(WX_OPEN_BASE_URL, "/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect"), + /** + * oauth2授权的url连接. + */ + CONNECT_OAUTH2_AUTHORIZE_URL(WX_OPEN_BASE_URL, "/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s&connect_redirect=1#wechat_redirect"), + /** + * 获取公众号的自动回复规则. + */ + GET_CURRENT_AUTOREPLY_INFO_URL(WX_API_BASE_URL, "/cgi-bin/get_current_autoreply_info"), + /** + * 公众号调用或第三方平台帮公众号调用对公众号的所有api调用(包括第三方帮其调用)次数进行清零. + */ + CLEAR_QUOTA_URL(WX_API_BASE_URL, "/cgi-bin/clear_quota"); + + private String prefix; + private String path; + + @Override + public String getUrl() { + return this.prefix + this.path; + } + } + + @AllArgsConstructor + enum Marketing implements WxMpApiUrl { + /** + * sets add. + */ + USER_ACTION_SETS_ADD(WX_API_BASE_URL, "/marketing/user_action_sets/add?version=v1.0"), + /** + * get. + */ + USER_ACTION_SETS_GET(WX_API_BASE_URL, "/marketing/user_action_sets/get"), + /** + * add. + */ + USER_ACTIONS_ADD(WX_API_BASE_URL, "/marketing/user_actions/add?version=v1.0"), + /** + * get. + */ + WECHAT_AD_LEADS_GET(WX_API_BASE_URL, "/marketing/wechat_ad_leads/get"); + + private String prefix; + private String path; + + @Override + public String getUrl() { + return this.prefix + this.path; + } + } + + @AllArgsConstructor + enum Menu implements WxMpApiUrl { + /** + * get_current_selfmenu_info. + */ + GET_CURRENT_SELFMENU_INFO(WX_API_BASE_URL, "/cgi-bin/get_current_selfmenu_info"), + /** + * trymatch. + */ + MENU_TRYMATCH(WX_API_BASE_URL, "/cgi-bin/menu/trymatch"), + /** + * get. + */ + MENU_GET(WX_API_BASE_URL, "/cgi-bin/menu/get"), + /** + * delconditional. + */ + MENU_DELCONDITIONAL(WX_API_BASE_URL, "/cgi-bin/menu/delconditional"), + /** + * delete. + */ + MENU_DELETE(WX_API_BASE_URL, "/cgi-bin/menu/delete"), + /** + * create. + */ + MENU_CREATE(WX_API_BASE_URL, "/cgi-bin/menu/create"), + /** + * addconditional. + */ + MENU_ADDCONDITIONAL(WX_API_BASE_URL, "/cgi-bin/menu/addconditional"); + + private String prefix; + private String path; + + @Override + public String getUrl() { + return this.prefix + this.path; + } + } + + + @AllArgsConstructor + enum Qrcode implements WxMpApiUrl { + /** + * create. + */ + QRCODE_CREATE(WX_API_BASE_URL, "/cgi-bin/qrcode/create"), + /** + * showqrcode. + */ + SHOW_QRCODE(WX_MP_BASE_URL, "/cgi-bin/showqrcode"), + /** + * showqrcode. + */ + SHOW_QRCODE_WITH_TICKET(WX_MP_BASE_URL, "/cgi-bin/showqrcode?ticket=%s"); + + private String prefix; + private String path; + + @Override + public String getUrl() { + return this.prefix + this.path; + } + } + + @AllArgsConstructor + enum ShakeAround implements WxMpApiUrl { + /** + * getshakeinfo. + */ + SHAKEAROUND_USER_GETSHAKEINFO(WX_API_BASE_URL, "/shakearound/user/getshakeinfo"), + /** + * add. + */ + SHAKEAROUND_PAGE_ADD(WX_API_BASE_URL, "/shakearound/page/add"), + /** + * bindpage. + */ + SHAKEAROUND_DEVICE_BINDPAGE(WX_API_BASE_URL, "/shakearound/device/bindpage"), + /** + * search. + */ + SHAKEAROUND_RELATION_SEARCH(WX_API_BASE_URL, "/shakearound/relation/search"); + + + private String prefix; + private String path; + + @Override + public String getUrl() { + return this.prefix + this.path; + } + } + + @AllArgsConstructor + enum SubscribeMsg implements WxMpApiUrl { + /** + * subscribemsg. + */ + SUBSCRIBE_MESSAGE_AUTHORIZE_URL(WX_MP_BASE_URL, "/mp/subscribemsg?action=get_confirm&appid=%s&scene=%d&template_id=%s&redirect_url=%s&reserved=%s#wechat_redirect"), + /** + * subscribe. + */ + SEND_MESSAGE_URL(WX_API_BASE_URL, "/cgi-bin/message/template/subscribe"); + + private String prefix; + private String path; + + @Override + public String getUrl() { + return this.prefix + this.path; + } + } + + @AllArgsConstructor + enum TemplateMsg implements WxMpApiUrl { + /** + * send. + */ + MESSAGE_TEMPLATE_SEND(WX_API_BASE_URL, "/cgi-bin/message/template/send"), + /** + * api_set_industry. + */ + TEMPLATE_API_SET_INDUSTRY(WX_API_BASE_URL, "/cgi-bin/template/api_set_industry"), + /** + * get_industry. + */ + TEMPLATE_GET_INDUSTRY(WX_API_BASE_URL, "/cgi-bin/template/get_industry"), + /** + * api_add_template. + */ + TEMPLATE_API_ADD_TEMPLATE(WX_API_BASE_URL, "/cgi-bin/template/api_add_template"), + /** + * get_all_private_template. + */ + TEMPLATE_GET_ALL_PRIVATE_TEMPLATE(WX_API_BASE_URL, "/cgi-bin/template/get_all_private_template"), + /** + * del_private_template. + */ + TEMPLATE_DEL_PRIVATE_TEMPLATE(WX_API_BASE_URL, "/cgi-bin/template/del_private_template"); + + private String prefix; + private String path; + + @Override + public String getUrl() { + return this.prefix + this.path; + } + } + + @AllArgsConstructor + enum UserBlacklist implements WxMpApiUrl { + /** + * getblacklist. + */ + GETBLACKLIST(WX_API_BASE_URL, "/cgi-bin/tags/members/getblacklist"), + /** + * batchblacklist. + */ + BATCHBLACKLIST(WX_API_BASE_URL, "/cgi-bin/tags/members/batchblacklist"), + /** + * batchunblacklist. + */ + BATCHUNBLACKLIST(WX_API_BASE_URL, "/cgi-bin/tags/members/batchunblacklist"); + + private String prefix; + private String path; + + @Override + public String getUrl() { + return this.prefix + this.path; + } + } + + @AllArgsConstructor + enum UserTag implements WxMpApiUrl { + /** + * create. + */ + TAGS_CREATE(WX_API_BASE_URL, "/cgi-bin/tags/create"), + /** + * get. + */ + TAGS_GET(WX_API_BASE_URL, "/cgi-bin/tags/get"), + /** + * update. + */ + TAGS_UPDATE(WX_API_BASE_URL, "/cgi-bin/tags/update"), + /** + * delete. + */ + TAGS_DELETE(WX_API_BASE_URL, "/cgi-bin/tags/delete"), + /** + * get. + */ + TAG_GET(WX_API_BASE_URL, "/cgi-bin/user/tag/get"), + /** + * batchtagging. + */ + TAGS_MEMBERS_BATCHTAGGING(WX_API_BASE_URL, "/cgi-bin/tags/members/batchtagging"), + /** + * batchuntagging. + */ + TAGS_MEMBERS_BATCHUNTAGGING(WX_API_BASE_URL, "/cgi-bin/tags/members/batchuntagging"), + /** + * getidlist. + */ + TAGS_GETIDLIST(WX_API_BASE_URL, "/cgi-bin/tags/getidlist"); + + private String prefix; + private String path; + + @Override + public String getUrl() { + return this.prefix + this.path; + } + } + + @AllArgsConstructor + enum Wifi implements WxMpApiUrl { + /** + * list. + */ + BIZWIFI_SHOP_LIST(WX_API_BASE_URL, "/bizwifi/shop/list"); + + private String prefix; + private String path; + + @Override + public String getUrl() { + return this.prefix + this.path; + } + } + + @AllArgsConstructor + enum AiOpen implements WxMpApiUrl { + /** + * translatecontent. + */ + TRANSLATE_URL(WX_API_BASE_URL, "/cgi-bin/media/voice/translatecontent?lfrom=%s<o=%s"), + /** + * addvoicetorecofortext. + */ + VOICE_UPLOAD_URL(WX_API_BASE_URL, "/cgi-bin/media/voice/addvoicetorecofortext?format=%s&voice_id=%s&lang=%s"), + /** + * queryrecoresultfortext. + */ + VOICE_QUERY_RESULT_URL(WX_API_BASE_URL, "/cgi-bin/media/voice/queryrecoresultfortext"); + + private String prefix; + private String path; + + @Override + public String getUrl() { + return this.prefix + this.path; + } + } + + @AllArgsConstructor + enum Card implements WxMpApiUrl { + /** + * create. + */ + CARD_CREATE(WX_API_BASE_URL, "/card/create"), + /** + * get. + */ + CARD_GET(WX_API_BASE_URL, "/card/get"), + /** + * wx_card. + */ + CARD_GET_TICKET(WX_API_BASE_URL, "/cgi-bin/ticket/getticket?type=wx_card"), + /** + * decrypt. + */ + CARD_CODE_DECRYPT(WX_API_BASE_URL, "/card/code/decrypt"), + /** + * get. + */ + CARD_CODE_GET(WX_API_BASE_URL, "/card/code/get"), + /** + * consume. + */ + CARD_CODE_CONSUME(WX_API_BASE_URL, "/card/code/consume"), + /** + * mark. + */ + CARD_CODE_MARK(WX_API_BASE_URL, "/card/code/mark"), + /** + * set. + */ + CARD_TEST_WHITELIST(WX_API_BASE_URL, "/card/testwhitelist/set"), + /** + * create. + */ + CARD_QRCODE_CREATE(WX_API_BASE_URL, "/card/qrcode/create"), + /** + * create. + */ + CARD_LANDING_PAGE_CREATE(WX_API_BASE_URL, "/card/landingpage/create"), + /** + * 将用户的卡券设置为失效状态. + */ + CARD_CODE_UNAVAILABLE(WX_API_BASE_URL, "/card/code/unavailable"), + /** + * 卡券删除. + */ + CARD_DELETE(WX_API_BASE_URL, "/card/delete"); + + private String prefix; + private String path; + + @Override + public String getUrl() { + return this.prefix + this.path; + } + } + + @AllArgsConstructor + enum DataCube implements WxMpApiUrl { + /** + * getusersummary. + */ + GET_USER_SUMMARY(WX_API_BASE_URL, "/datacube/getusersummary"), + /** + * getusercumulate. + */ + GET_USER_CUMULATE(WX_API_BASE_URL, "/datacube/getusercumulate"), + /** + * getarticlesummary. + */ + GET_ARTICLE_SUMMARY(WX_API_BASE_URL, "/datacube/getarticlesummary"), + /** + * getarticletotal. + */ + GET_ARTICLE_TOTAL(WX_API_BASE_URL, "/datacube/getarticletotal"), + /** + * getuserread. + */ + GET_USER_READ(WX_API_BASE_URL, "/datacube/getuserread"), + /** + * getuserreadhour. + */ + GET_USER_READ_HOUR(WX_API_BASE_URL, "/datacube/getuserreadhour"), + /** + * getusershare. + */ + GET_USER_SHARE(WX_API_BASE_URL, "/datacube/getusershare"), + /** + * getusersharehour. + */ + GET_USER_SHARE_HOUR(WX_API_BASE_URL, "/datacube/getusersharehour"), + /** + * getupstreammsg. + */ + GET_UPSTREAM_MSG(WX_API_BASE_URL, "/datacube/getupstreammsg"), + /** + * getupstreammsghour. + */ + GET_UPSTREAM_MSG_HOUR(WX_API_BASE_URL, "/datacube/getupstreammsghour"), + /** + * getupstreammsgweek. + */ + GET_UPSTREAM_MSG_WEEK(WX_API_BASE_URL, "/datacube/getupstreammsgweek"), + /** + * getupstreammsgmonth. + */ + GET_UPSTREAM_MSG_MONTH(WX_API_BASE_URL, "/datacube/getupstreammsgmonth"), + /** + * getupstreammsgdist. + */ + GET_UPSTREAM_MSG_DIST(WX_API_BASE_URL, "/datacube/getupstreammsgdist"), + /** + * getupstreammsgdistweek. + */ + GET_UPSTREAM_MSG_DIST_WEEK(WX_API_BASE_URL, "/datacube/getupstreammsgdistweek"), + /** + * getupstreammsgdistmonth. + */ + GET_UPSTREAM_MSG_DIST_MONTH(WX_API_BASE_URL, "/datacube/getupstreammsgdistmonth"), + /** + * getinterfacesummary. + */ + GET_INTERFACE_SUMMARY(WX_API_BASE_URL, "/datacube/getinterfacesummary"), + /** + * getinterfacesummaryhour. + */ + GET_INTERFACE_SUMMARY_HOUR(WX_API_BASE_URL, "/datacube/getinterfacesummaryhour"); + + private String prefix; + private String path; + + @Override + public String getUrl() { + return this.prefix + this.path; + } + } + + @AllArgsConstructor + enum Kefu implements WxMpApiUrl { + /** + * send. + */ + MESSAGE_CUSTOM_SEND(WX_API_BASE_URL, "/cgi-bin/message/custom/send"), + /** + * getkflist. + */ + GET_KF_LIST(WX_API_BASE_URL, "/cgi-bin/customservice/getkflist"), + /** + * getonlinekflist. + */ + GET_ONLINE_KF_LIST(WX_API_BASE_URL, "/cgi-bin/customservice/getonlinekflist"), + /** + * add. + */ + KFACCOUNT_ADD(WX_API_BASE_URL, "/customservice/kfaccount/add"), + /** + * update. + */ + KFACCOUNT_UPDATE(WX_API_BASE_URL, "/customservice/kfaccount/update"), + /** + * inviteworker. + */ + KFACCOUNT_INVITE_WORKER(WX_API_BASE_URL, "/customservice/kfaccount/inviteworker"), + /** + * uploadheadimg. + */ + KFACCOUNT_UPLOAD_HEAD_IMG(WX_API_BASE_URL, "/customservice/kfaccount/uploadheadimg?kf_account=%s"), + /** + * del kfaccount. + */ + KFACCOUNT_DEL(WX_API_BASE_URL, "/customservice/kfaccount/del?kf_account=%s"), + /** + * create. + */ + KFSESSION_CREATE(WX_API_BASE_URL, "/customservice/kfsession/create"), + /** + * close. + */ + KFSESSION_CLOSE(WX_API_BASE_URL, "/customservice/kfsession/close"), + /** + * getsession. + */ + KFSESSION_GET_SESSION(WX_API_BASE_URL, "/customservice/kfsession/getsession?openid=%s"), + /** + * getsessionlist. + */ + KFSESSION_GET_SESSION_LIST(WX_API_BASE_URL, "/customservice/kfsession/getsessionlist?kf_account=%s"), + /** + * getwaitcase. + */ + KFSESSION_GET_WAIT_CASE(WX_API_BASE_URL, "/customservice/kfsession/getwaitcase"), + /** + * getmsglist. + */ + MSG_RECORD_LIST(WX_API_BASE_URL, "/customservice/msgrecord/getmsglist"), + /** + * typing. + */ + CUSTOM_TYPING(WX_API_BASE_URL, "/cgi-bin/message/custom/typing"); + + private String prefix; + private String path; + + @Override + public String getUrl() { + return this.prefix + this.path; + } + } + + @AllArgsConstructor + enum MassMessage implements WxMpApiUrl { + /** + * 上传群发用的图文消息. + */ + MEDIA_UPLOAD_NEWS_URL(WX_API_BASE_URL, "/cgi-bin/media/uploadnews"), + /** + * 上传群发用的视频. + */ + MEDIA_UPLOAD_VIDEO_URL(WX_API_BASE_URL, "/cgi-bin/media/uploadvideo"), + /** + * 分组群发消息. + */ + MESSAGE_MASS_SENDALL_URL(WX_API_BASE_URL, "/cgi-bin/message/mass/sendall"), + /** + * 按openId列表群发消息. + */ + MESSAGE_MASS_SEND_URL(WX_API_BASE_URL, "/cgi-bin/message/mass/send"), + /** + * 群发消息预览接口. + */ + MESSAGE_MASS_PREVIEW_URL(WX_API_BASE_URL, "/cgi-bin/message/mass/preview"), + /** + * 删除群发接口. + */ + MESSAGE_MASS_DELETE_URL(WX_API_BASE_URL, "/cgi-bin/message/mass/delete"); + + private String prefix; + private String path; + + @Override + public String getUrl() { + return this.prefix + this.path; + } + } + + @AllArgsConstructor + enum Material implements WxMpApiUrl { + /** + * get. + */ + MEDIA_GET_URL(WX_API_BASE_URL, "/cgi-bin/media/get"), + /** + * upload. + */ + MEDIA_UPLOAD_URL(WX_API_BASE_URL, "/cgi-bin/media/upload?type=%s"), + /** + * uploadimg. + */ + IMG_UPLOAD_URL(WX_API_BASE_URL, "/cgi-bin/media/uploadimg"), + /** + * add_material. + */ + MATERIAL_ADD_URL(WX_API_BASE_URL, "/cgi-bin/material/add_material?type=%s"), + /** + * add_news. + */ + NEWS_ADD_URL(WX_API_BASE_URL, "/cgi-bin/material/add_news"), + /** + * get_material. + */ + MATERIAL_GET_URL(WX_API_BASE_URL, "/cgi-bin/material/get_material"), + /** + * update_news. + */ + NEWS_UPDATE_URL(WX_API_BASE_URL, "/cgi-bin/material/update_news"), + /** + * del_material. + */ + MATERIAL_DEL_URL(WX_API_BASE_URL, "/cgi-bin/material/del_material"), + /** + * get_materialcount. + */ + MATERIAL_GET_COUNT_URL(WX_API_BASE_URL, "/cgi-bin/material/get_materialcount"), + /** + * batchget_material. + */ + MATERIAL_BATCHGET_URL(WX_API_BASE_URL, "/cgi-bin/material/batchget_material"); + + private String prefix; + private String path; + + @Override + public String getUrl() { + return this.prefix + this.path; + } + } + + @AllArgsConstructor + enum MemberCard implements WxMpApiUrl { + /** + * create. + */ + MEMBER_CARD_CREATE(WX_API_BASE_URL, "/card/create"), + /** + * activate. + */ + MEMBER_CARD_ACTIVATE(WX_API_BASE_URL, "/card/membercard/activate"), + /** + * get userinfo. + */ + MEMBER_CARD_USER_INFO_GET(WX_API_BASE_URL, "/card/membercard/userinfo/get"), + /** + * updateuser. + */ + MEMBER_CARD_UPDATE_USER(WX_API_BASE_URL, "/card/membercard/updateuser"), + /** + * 会员卡激活之微信开卡接口(wx_activate=true情况调用). + */ + MEMBER_CARD_ACTIVATE_USER_FORM(WX_API_BASE_URL, "/card/membercard/activateuserform/set"), + /** + * 获取会员卡开卡插件参数. + */ + MEMBER_CARD_ACTIVATE_URL(WX_API_BASE_URL, "/card/membercard/activate/geturl"), + /** + * 会员卡信息更新. + */ + MEMBER_CARD_UPDATE(WX_API_BASE_URL, "/card/update"), + /** + * 跳转型会员卡开卡字段. + * 获取用户提交资料(wx_activate=true情况调用),开发者根据activate_ticket获取到用户填写的信息 + */ + MEMBER_CARD_ACTIVATE_TEMP_INFO(WX_API_BASE_URL, "/card/membercard/activatetempinfo/get"); + + private String prefix; + private String path; + + @Override + public String getUrl() { + return this.prefix + this.path; + } + } + + @AllArgsConstructor + enum Store implements WxMpApiUrl { + /** + * getwxcategory. + */ + POI_GET_WX_CATEGORY_URL(WX_API_BASE_URL, "/cgi-bin/poi/getwxcategory"), + /** + * updatepoi. + */ + POI_UPDATE_URL(WX_API_BASE_URL, "/cgi-bin/poi/updatepoi"), + /** + * getpoilist. + */ + POI_LIST_URL(WX_API_BASE_URL, "/cgi-bin/poi/getpoilist"), + /** + * delpoi. + */ + POI_DEL_URL(WX_API_BASE_URL, "/cgi-bin/poi/delpoi"), + /** + * getpoi. + */ + POI_GET_URL(WX_API_BASE_URL, "/cgi-bin/poi/getpoi"), + /** + * addpoi. + */ + POI_ADD_URL(WX_API_BASE_URL, "/cgi-bin/poi/addpoi"); + + private String prefix; + private String path; + + @Override + public String getUrl() { + return this.prefix + this.path; + } + } + + + @AllArgsConstructor + enum User implements WxMpApiUrl { + /** + * batchget. + */ + USER_INFO_BATCH_GET_URL(WX_API_BASE_URL, "/cgi-bin/user/info/batchget"), + /** + * get. + */ + USER_GET_URL(WX_API_BASE_URL, "/cgi-bin/user/get"), + /** + * info. + */ + USER_INFO_URL(WX_API_BASE_URL, "/cgi-bin/user/info"), + /** + * updateremark. + */ + USER_INFO_UPDATE_REMARK_URL(WX_API_BASE_URL, "/cgi-bin/user/info/updateremark"), + /** + * changeopenid. + */ + USER_CHANGE_OPENID_URL(WX_API_BASE_URL, "/cgi-bin/changeopenid"); + + private String prefix; + private String path; + + @Override + public String getUrl() { + return this.prefix + this.path; + } + } +} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java index 507ab31b6b..1f0a01b46e 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java @@ -1,5 +1,6 @@ package me.chanjar.weixin.mp.api; +import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; @@ -12,6 +13,7 @@ import java.util.concurrent.Future; @Test +@Slf4j public class WxMpBusyRetryTest { @DataProvider(name = "getService") @@ -22,7 +24,7 @@ public Object[][] getService() { public synchronized T executeInternal( RequestExecutor executor, String uri, E data) throws WxErrorException { - this.log.info("Executed"); + log.info("Executed"); throw new WxErrorException(WxError.builder().errorCode(-1).build()); } }; @@ -34,7 +36,7 @@ public synchronized T executeInternal( @Test(dataProvider = "getService", expectedExceptions = RuntimeException.class) public void testRetry(WxMpService service) throws WxErrorException { - service.execute(null, null, null); + service.execute(null, (String)null, null); } @Test(dataProvider = "getService") @@ -47,7 +49,7 @@ public void run() { try { System.out.println("====================="); System.out.println(Thread.currentThread().getName() + ": testRetry"); - service.execute(null, null, null); + service.execute(null, (String)null, null); } catch (WxErrorException e) { throw new RuntimeException(e); } catch (RuntimeException e) { diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpJsAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpJsAPITest.java index 0b14d9564b..c9df2c8153 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpJsAPITest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpJsAPITest.java @@ -3,24 +3,22 @@ import com.google.inject.Inject; import me.chanjar.weixin.common.util.crypto.SHA1; import me.chanjar.weixin.mp.api.test.ApiTestModule; -import org.testng.*; -import org.testng.annotations.*; +import org.testng.Assert; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; /** * 测试jsapi ticket接口 * * @author chanjarster */ -@Test(groups = "jsAPI", dependsOnGroups = "baseAPI") +@Test @Guice(modules = ApiTestModule.class) public class WxMpJsAPITest { @Inject protected WxMpService wxService; - - - public void test() { long timestamp = 1419835025L; String url = "http://omstest.vmall.com:23568/thirdparty/wechat/vcode/gotoshare?quantity=1&batchName=MATE7"; diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImplTest.java index fa73b8f4d8..89069bd29f 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImplTest.java @@ -1,25 +1,27 @@ package me.chanjar.weixin.mp.api.impl; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import me.chanjar.weixin.mp.api.WxMpUserService; -import me.chanjar.weixin.mp.bean.result.WxMpChangeOpenid; -import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import org.testng.*; -import org.testng.annotations.*; - import com.google.inject.Inject; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.test.ApiTestModule; import me.chanjar.weixin.mp.api.test.TestConfigStorage; import me.chanjar.weixin.mp.bean.WxMpUserQuery; +import me.chanjar.weixin.mp.bean.result.WxMpChangeOpenid; import me.chanjar.weixin.mp.bean.result.WxMpUser; import me.chanjar.weixin.mp.bean.result.WxMpUserList; +import me.chanjar.weixin.mp.enums.WxMpApiUrl; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import org.testng.Assert; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.User.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -86,8 +88,7 @@ public void testUserList() throws WxErrorException { public void testChangeOpenid() throws WxErrorException { List openids = new ArrayList<>(); openids.add(this.configProvider.getOpenid()); - List wxMpChangeOpenidList = this.wxService.getUserService() - .changeOpenid("原公众号appid", openids); + List wxMpChangeOpenidList = this.wxService.getUserService().changeOpenid("原公众号appid", openids); Assert.assertNotNull(wxMpChangeOpenidList); Assert.assertEquals(1, wxMpChangeOpenidList.size()); WxMpChangeOpenid wxMpChangeOpenid = wxMpChangeOpenidList.get(0); @@ -98,6 +99,7 @@ public void testChangeOpenid() throws WxErrorException { public static class MockTest { private WxMpService wxService = mock(WxMpService.class); + @Test public void testMockChangeOpenid() throws WxErrorException { List openids = new ArrayList<>(); @@ -109,9 +111,8 @@ public void testMockChangeOpenid() throws WxErrorException { map.put("openid_list", openids); String returnJson = "{\"errcode\": 0,\"errmsg\": \"ok\",\"result_list\": [{\"ori_openid\": \"oEmYbwN-n24jxvk4Sox81qedINkQ\",\"new_openid\": \"o2FwqwI9xCsVadFah_HtpPfaR-X4\",\"err_msg\": \"ok\"},{\"ori_openid\": \"oEmYbwH9uVd4RKJk7ZZg6SzL6tTo\",\"err_msg\": \"ori_openid error\"}]}"; - when(wxService.post(WxMpUserService.USER_CHANGE_OPENID_URL, WxMpGsonBuilder.create().toJson(map))).thenReturn(returnJson); - List wxMpChangeOpenidList = this.wxService.getUserService() - .changeOpenid(fromAppid, openids); + when(wxService.post(USER_CHANGE_OPENID_URL, WxMpGsonBuilder.create().toJson(map))).thenReturn(returnJson); + List wxMpChangeOpenidList = this.wxService.getUserService().changeOpenid(fromAppid, openids); Assert.assertNotNull(wxMpChangeOpenidList); Assert.assertEquals(2, wxMpChangeOpenidList.size()); WxMpChangeOpenid wxMpChangeOpenid = wxMpChangeOpenidList.get(0); From 6dc9d378c5b1ae0a2f3bae7eea82e55a8f6434f5 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Thu, 6 Jun 2019 14:16:04 +0800 Subject: [PATCH 17/74] =?UTF-8?q?=E8=A1=A5=E5=85=85=E7=BC=BA=E5=A4=B1?= =?UTF-8?q?=E7=9A=84serialVersionUID?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/mp/api/impl/WxMpSubscribeMsgServiceImpl.java | 8 ++++---- .../binarywang/wxpay/bean/order/WxPayAppOrderResult.java | 2 ++ .../binarywang/wxpay/bean/order/WxPayMpOrderResult.java | 2 ++ .../binarywang/wxpay/bean/order/WxPayMwebOrderResult.java | 2 ++ .../wxpay/bean/order/WxPayNativeOrderResult.java | 2 ++ 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpSubscribeMsgServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpSubscribeMsgServiceImpl.java index d68342869e..fb6559ba13 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpSubscribeMsgServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpSubscribeMsgServiceImpl.java @@ -7,9 +7,9 @@ import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpSubscribeMsgService; import me.chanjar.weixin.mp.bean.subscribe.WxMpSubscribeMessage; -import me.chanjar.weixin.mp.enums.WxMpApiUrl; -import static me.chanjar.weixin.mp.enums.WxMpApiUrl.SubscribeMsg.*; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.SubscribeMsg.SEND_MESSAGE_URL; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.SubscribeMsg.SUBSCRIBE_MESSAGE_AUTHORIZE_URL; /** * 一次性订阅消息接口. @@ -24,8 +24,8 @@ public class WxMpSubscribeMsgServiceImpl implements WxMpSubscribeMsgService { @Override public String subscribeMsgAuthorizationUrl(String redirectURI, int scene, String reserved) { WxMpConfigStorage storage = this.wxMpService.getWxMpConfigStorage(); - return String.format(SUBSCRIBE_MESSAGE_AUTHORIZE_URL.getUrl(), - storage.getAppId(), scene, storage.getTemplateId(), URIUtil.encodeURIComponent(redirectURI), reserved); + return String.format(SUBSCRIBE_MESSAGE_AUTHORIZE_URL.getUrl(), storage.getAppId(), scene, storage.getTemplateId(), + URIUtil.encodeURIComponent(redirectURI), reserved); } @Override diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayAppOrderResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayAppOrderResult.java index 2ff290056f..c37efadbb1 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayAppOrderResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayAppOrderResult.java @@ -17,6 +17,8 @@ @Data @Builder public class WxPayAppOrderResult implements Serializable { + private static final long serialVersionUID = 5408678833978707228L; + private String sign; private String prepayId; private String partnerId; diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMpOrderResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMpOrderResult.java index ad6d27b507..7fe7234f1c 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMpOrderResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMpOrderResult.java @@ -18,6 +18,8 @@ @Data @Builder public class WxPayMpOrderResult implements Serializable { + private static final long serialVersionUID = -7966682379048446567L; + private String appId; private String timeStamp; private String nonceStr; diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMwebOrderResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMwebOrderResult.java index a2240f5dac..78487f9966 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMwebOrderResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMwebOrderResult.java @@ -17,6 +17,8 @@ @Data @AllArgsConstructor public class WxPayMwebOrderResult implements Serializable { + private static final long serialVersionUID = 8866329695767762066L; + @XStreamAlias("mwebUrl") private String mwebUrl; } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayNativeOrderResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayNativeOrderResult.java index 4a371c1fca..134f5cf883 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayNativeOrderResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayNativeOrderResult.java @@ -16,5 +16,7 @@ @Data @AllArgsConstructor public class WxPayNativeOrderResult implements Serializable { + private static final long serialVersionUID = 887792717425241444L; + private String codeUrl; } From 2422a28f9abc83ad69b86928ff16f637a2be9d4c Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 9 Jun 2019 19:51:02 +0800 Subject: [PATCH 18/74] =?UTF-8?q?#1055=20=E5=A2=9E=E5=8A=A0=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E5=8D=A1=E5=88=B8=E4=BA=8C=E7=BB=B4=E7=A0=81=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E7=BC=BA=E5=A4=B1=E7=9A=84=E4=B8=80=E4=BA=9B=E5=8F=82?= =?UTF-8?q?=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/mp/api/WxMpCardService.java | 72 +++++++++++++------ .../mp/api/impl/WxMpCardServiceImpl.java | 19 ++++- .../mp/api/impl/WxMpCardServiceImplTest.java | 29 ++++++-- 3 files changed, 92 insertions(+), 28 deletions(-) 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 8b9a599448..f5131e8f98 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 @@ -13,6 +13,8 @@ public interface WxMpCardService { /** * 得到WxMpService. + * + * @return WxMpService */ WxMpService getWxMpService(); @@ -20,6 +22,7 @@ public interface WxMpCardService { * 获得卡券api_ticket,不强制刷新卡券api_ticket. * * @return 卡券api_ticket + * @throws WxErrorException 异常 * @see #getCardApiTicket(boolean) */ String getCardApiTicket() throws WxErrorException; @@ -34,7 +37,7 @@ public interface WxMpCardService { * * @param forceRefresh 强制刷新 * @return 卡券api_ticket - * @throws WxErrorException + * @throws WxErrorException 异常 */ String getCardApiTicket(boolean forceRefresh) throws WxErrorException; @@ -47,18 +50,19 @@ public interface WxMpCardService { * .9F.E6.88.90.E7.AE.97.E6.B3.95 *
* - * @param optionalSignParam 参与签名的参数数组。 - * 可以为下列字段:app_id, card_id, card_type, code, openid, location_id + * @param optionalSignParam 参与签名的参数数组。可以为下列字段:app_id, card_id, card_type, code, openid, location_id *
注意:当做wx.chooseCard调用时,必须传入app_id参与签名,否则会造成签名失败导致拉取卡券列表为空 * @return 卡券Api签名对象 + * @throws WxErrorException 异常 */ - WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws WxErrorException; + WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws WxErrorException; /** * 卡券Code解码. * * @param encryptCode 加密Code,通过JSSDK的chooseCard接口获得 * @return 解密后的Code + * @throws WxErrorException 异常 */ String decryptCardCode(String encryptCode) throws WxErrorException; @@ -70,16 +74,16 @@ public interface WxMpCardService { * @param code 单张卡券的唯一标准 * @param checkConsume 是否校验code核销状态,填入true和false时的code异常状态返回数据不同 * @return WxMpCardResult对象 + * @throws WxErrorException 异常 */ - WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) - throws WxErrorException; + WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) throws WxErrorException; /** * 卡券Code核销。核销失败会抛出异常 * * @param code 单张卡券的唯一标准 - * @return 调用返回的JSON字符串。 - *
可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。 + * @return 调用返回的JSON字符串。可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。 + * @throws WxErrorException 异常 */ String consumeCardCode(String code) throws WxErrorException; @@ -88,13 +92,13 @@ WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) * * @param code 单张卡券的唯一标准 * @param cardId 当自定义Code卡券时需要传入card_id - * @return 调用返回的JSON字符串。 - *
可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。 + * @return 调用返回的JSON字符串。可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。 + * @throws WxErrorException 异常 */ String consumeCardCode(String code, String cardId) throws WxErrorException; /** - * 卡券Mark接口。 + * 卡券Mark接口. * 开发者在帮助消费者核销卡券之前,必须帮助先将此code(卡券串码)与一个openid绑定(即mark住), * 才能进一步调用核销接口,否则报错。 * @@ -102,6 +106,7 @@ WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) * @param cardId 卡券的ID * @param openId 用券用户的openid * @param isMark 是否要mark(占用)这个code,填写true或者false,表示占用或解除占用 + * @throws WxErrorException 异常 */ void markCardCode(String code, String cardId, String openId, boolean isMark) throws WxErrorException; @@ -113,6 +118,7 @@ WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) * @return 返回的卡券详情JSON字符串 *
[注] 由于返回的JSON格式过于复杂,难以定义其对应格式的Bean并且难以维护,因此只返回String格式的JSON串。 *
可由 com.google.gson.JsonParser#parse 等方法直接取JSON串中的某个字段。 + * @throws WxErrorException 异常 */ String getCardDetail(String cardId) throws WxErrorException; @@ -120,14 +126,17 @@ WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) * 添加测试白名单. * * @param openid 用户的openid - * @return + * @return string + * @throws WxErrorException 异常 */ String addTestWhiteList(String openid) throws WxErrorException; /** - * @param cardCreateMessage - * @return - * @throws WxErrorException + * 创建卡券. + * + * @param cardCreateMessage 请求 + * @return result + * @throws WxErrorException 异常 */ WxMpCardCreateResult createCard(WxMpCardCreateMessage cardCreateMessage) throws WxErrorException; @@ -137,6 +146,7 @@ WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) * @param cardId 卡券编号 * @param outerStr 二维码标识 * @return WxMpCardQrcodeCreateResult + * @throws WxErrorException 异常 */ WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr) throws WxErrorException; @@ -145,17 +155,33 @@ WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) * * @param cardId 卡券编号 * @param outerStr 二维码标识 - * @param expiresIn 失效时间,单位秒,不填默认365天 + * @param expiresIn 指定二维码的有效时间,范围是60 ~ 1800秒。不填默认为365天有效 * @return WxMpCardQrcodeCreateResult + * @throws WxErrorException 异常 */ WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr, int expiresIn) throws WxErrorException; + /** + * 创建卡券二维码. + * + * @param cardId 卡券编号 + * @param outerStr 用户首次领卡时,会通过 领取事件推送 给商户; 对于会员卡的二维码,用户每次扫码打开会员卡后点击任何url,会将该值拼入url中,方便开发者定位扫码来源 + * @param expiresIn 指定二维码的有效时间,范围是60 ~ 1800秒。不填默认为365天有效 + * @param isUniqueCode 指定下发二维码,生成的二维码随机分配一个code,领取后不可再次扫描。填写true或false。默认false,注意填写该字段时,卡券须通过审核且库存不为0。 + * @param code 卡券Code码,use_custom_code字段为true的卡券必须填写,非自定义code和导入code模式的卡券不必填写。 + * @param openid 指定领取者的openid,只有该用户能领取。bind_openid字段为true的卡券必须填写,非指定openid不必填写。 + * @return WxMpCardQrcodeCreateResult + * @throws WxErrorException 异常 + */ + WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr, int expiresIn, String openid, + String code, boolean isUniqueCode) throws WxErrorException; + /** * 创建卡券货架. * * @param createRequest 货架创建参数 - * @return - * @throws WxErrorException + * @return WxMpCardLandingPageCreateResult + * @throws WxErrorException 异常 */ WxMpCardLandingPageCreateResult createLandingPage(WxMpCardLandingPageCreateRequest createRequest) throws WxErrorException; @@ -166,17 +192,17 @@ WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) * @param cardId 卡券编号 * @param code 用户会员卡号 * @param reason 设置为失效的原因 - * @return - * @throws WxErrorException + * @return result + * @throws WxErrorException 异常 */ String unavailableCardCode(String cardId, String code, String reason) throws WxErrorException; /** * 删除卡券接口. * - * @param cardId - * @return - * @throws WxErrorException + * @param cardId 卡券id + * @return 删除结果 + * @throws WxErrorException 异常 */ WxMpCardDeleteResult deleteCard(String cardId) 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 f232f1bb69..ec523f9a25 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 @@ -185,22 +185,39 @@ public WxMpCardCreateResult createCard(WxMpCardCreateMessage cardCreateMessage) @Override public WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr) throws WxErrorException { - return createQrcodeCard(cardId, outerStr, 0); + return this.createQrcodeCard(cardId, outerStr, 0); } @Override public WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr, int expiresIn) throws WxErrorException { + return this.createQrcodeCard(cardId, outerStr, expiresIn, null, null, false); + } + + @Override + public WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr, int expiresIn, String openid, + String code, boolean isUniqueCode) 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(); + if (openid != null) { + cardJson.addProperty("openid", openid); + } + + if (code != null) { + cardJson.addProperty("code", code); + } + + cardJson.addProperty("is_unique_code", isUniqueCode); cardJson.addProperty("card_id", cardId); cardJson.addProperty("outer_str", outerStr); actionInfoJson.add("card", cardJson); jsonObject.add("action_info", actionInfoJson); + return WxMpCardQrcodeCreateResult.fromJson(this.wxMpService.post(WxMpApiUrl.Card.CARD_QRCODE_CREATE, GSON.toJson(jsonObject))); } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImplTest.java index 37147e535a..b736f9089f 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImplTest.java @@ -9,8 +9,7 @@ import org.testng.annotations.Guice; import org.testng.annotations.Test; -import static org.testng.AssertJUnit.assertEquals; -import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.*; /** * 测试代码仅供参考,未做严格测试,因原接口作者并未提供单元测试代码 @@ -106,7 +105,6 @@ public void testUnavailableCardCode() throws Exception { @Test public void testCreateGrouponCard() throws WxErrorException { - BaseInfo base = new BaseInfo(); base.setLogoUrl("http://mmbiz.qpic.cn/mmbiz/iaL1LJM1mF9aRKPZJkmG8xXhiaHqkKSVMMWeN3hLut7X7hicFNjakmxibMLGWpXrEXB33367o7zHN0CwngnQY7zb7g/0"); base.setBrandName("测试优惠券"); @@ -202,8 +200,31 @@ public void testCreateGrouponCard() throws WxErrorException { public void testDeleteCard() throws Exception { String cardId = "pwkrWjtw7W4_l50kCQcZ1in1yS6g"; WxMpCardDeleteResult result = this.wxService.getCardService().deleteCard(cardId); - assertEquals(result.isSuccess(), true); + assertTrue(result.isSuccess()); System.out.println(result); } + @Test + public void testAddTestWhiteList() { + } + + @Test + public void testCreateCard() { + } + + @Test + public void testCreateQrcodeCard() { + } + + @Test + public void testCreateQrcodeCard1() { + } + + @Test + public void testCreateQrcodeCard2() { + } + + @Test + public void testCreateLandingPage() { + } } From 084ffcf8bbe8bdec2973f11053fe8ce5d9bb454c Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 9 Jun 2019 20:30:08 +0800 Subject: [PATCH 19/74] =?UTF-8?q?#1050=20=E5=AE=A2=E6=9C=8D=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E6=94=AF=E6=8C=81=E5=8F=91=E9=80=81=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chanjar/weixin/common/api/WxConsts.java | 9 +- .../weixin/mp/bean/kefu/WxMpKefuMessage.java | 37 +++-- .../mp/bean/message/WxMpXmlMessage.java | 8 +- .../mp/builder/kefu/WxMsgMenuBuilder.java | 46 ++++++ .../util/json/WxMpKefuMessageGsonAdapter.java | 154 ++++++++++-------- .../mp/bean/kefu/WxMpKefuMessageTest.java | 15 +- 6 files changed, 183 insertions(+), 86 deletions(-) create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/WxMsgMenuBuilder.java 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 9af7811c82..75cb54dcf3 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 @@ -85,14 +85,19 @@ public static class KefuMsgType { public static final String TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service"; /** - * 小程序卡片(要求小程序与公众号已关联) + * 小程序卡片(要求小程序与公众号已关联). */ public static final String MINIPROGRAMPAGE = "miniprogrampage"; /** - * 任务卡片消息 + * 任务卡片消息. */ public static final String TASKCARD = "taskcard"; + + /** + * 菜单消息. + */ + public static final String MSGMENU = "msgmenu"; } /** diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessage.java index 560add6042..b2966213b8 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessage.java @@ -10,7 +10,7 @@ import java.util.List; /** - * 客服消息 + * 客服消息. * * @author chanjarster */ @@ -34,64 +34,79 @@ public class WxMpKefuMessage implements Serializable { private String miniProgramPagePath; private List articles = new ArrayList<>(); + private String headContent; + private String tailContent; /** - * 获得文本消息builder + * 菜单消息里的菜单内容. + * 请使用逗号分割的形式将id和content连起来放在数组的里面 + */ + private String[] msgMenuList; + + /** + * 获得文本消息builder. */ public static TextBuilder TEXT() { return new TextBuilder(); } /** - * 获得图片消息builder + * 获得图片消息builder. */ public static ImageBuilder IMAGE() { return new ImageBuilder(); } /** - * 获得语音消息builder + * 获得语音消息builder. */ public static VoiceBuilder VOICE() { return new VoiceBuilder(); } /** - * 获得视频消息builder + * 获得视频消息builder. */ public static VideoBuilder VIDEO() { return new VideoBuilder(); } /** - * 获得音乐消息builder + * 获得音乐消息builder. */ public static MusicBuilder MUSIC() { return new MusicBuilder(); } /** - * 获得图文消息(点击跳转到外链)builder + * 获得图文消息(点击跳转到外链)builder. */ public static NewsBuilder NEWS() { return new NewsBuilder(); } /** - * 获得图文消息(点击跳转到图文消息页面)builder + * 获得图文消息(点击跳转到图文消息页面)builder. */ public static MpNewsBuilder MPNEWS() { return new MpNewsBuilder(); } /** - * 获得卡券消息builder + * 获得卡券消息builder. */ public static WxCardBuilder WXCARD() { return new WxCardBuilder(); } /** - * 小程序卡片 + * 获得菜单消息builder. + */ + public static WxMsgMenuBuilder MSGMENU() { + return new WxMsgMenuBuilder(); + } + + /** + * 小程序卡片. */ public static MiniProgramPageBuilder MINIPROGRAMPAGE() { return new MiniProgramPageBuilder(); @@ -110,8 +125,8 @@ public static MiniProgramPageBuilder MINIPROGRAMPAGE() { * {@link WxConsts.KefuMsgType#WXCARD} * {@link WxConsts.KefuMsgType#MINIPROGRAMPAGE} * {@link WxConsts.KefuMsgType#TASKCARD} + * {@link WxConsts.KefuMsgType#MSGMENU} *
- * */ public void setMsgType(String msgType) { this.msgType = msgType; 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 ba6fd227be..f8ed19bce4 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 @@ -634,11 +634,17 @@ public class WxMpXmlMessage implements Serializable { private String regionCode; /** - * 审核未通过的原因。 + * 审核未通过的原因. */ @XStreamAlias("ReasonMsg") private String reasonMsg; + /** + * 给用户发菜单消息类型的客服消息后,用户所点击的菜单ID. + */ + @XStreamAlias("bizmsgmenuid") + private String bizMsgMenuId; + public static WxMpXmlMessage fromXml(String xml) { //修改微信变态的消息内容格式,方便解析 xml = xml.replace("", ""); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/WxMsgMenuBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/WxMsgMenuBuilder.java new file mode 100644 index 0000000000..81d919ecd2 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/WxMsgMenuBuilder.java @@ -0,0 +1,46 @@ +package me.chanjar.weixin.mp.builder.kefu; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; + +/** + * 卡券消息builder + *
+ * 用法: WxMpKefuMessage m = WxMpKefuMessage.WXCARD().cardId(...).toUser(...).build();
+ * 
+ * + * @author Binary Wang + */ +public final class WxMsgMenuBuilder extends BaseBuilder { + private String headContent; + private String tailContent; + private String[] msgMenuList; + + public WxMsgMenuBuilder() { + this.msgType = WxConsts.KefuMsgType.MSGMENU; + } + + @Override + public WxMpKefuMessage build() { + WxMpKefuMessage m = super.build(); + m.setHeadContent(this.headContent); + m.setMsgMenuList(this.msgMenuList); + m.setTailContent(this.tailContent); + return m; + } + + public WxMsgMenuBuilder headContent(String headContent) { + this.headContent = headContent; + return this; + } + + public WxMsgMenuBuilder tailContent(String tailContent) { + this.tailContent = tailContent; + return this; + } + + public WxMsgMenuBuilder msgMenuList(String... msgMenuList) { + this.msgMenuList = msgMenuList; + return this; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpKefuMessageGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpKefuMessageGsonAdapter.java index 63389866f3..342a4b36a6 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpKefuMessageGsonAdapter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpKefuMessageGsonAdapter.java @@ -1,7 +1,6 @@ package me.chanjar.weixin.mp.util.json; import com.google.gson.*; -import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.api.WxConsts.KefuMsgType; import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; import org.apache.commons.lang3.StringUtils; @@ -16,77 +15,90 @@ public JsonElement serialize(WxMpKefuMessage message, Type typeOfSrc, JsonSerial messageJson.addProperty("touser", message.getToUser()); messageJson.addProperty("msgtype", message.getMsgType()); - if (WxConsts.KefuMsgType.TEXT.equals(message.getMsgType())) { - JsonObject text = new JsonObject(); - text.addProperty("content", message.getContent()); - messageJson.add("text", text); - } - - if (WxConsts.KefuMsgType.IMAGE.equals(message.getMsgType())) { - JsonObject image = new JsonObject(); - image.addProperty("media_id", message.getMediaId()); - messageJson.add("image", image); - } - - if (WxConsts.KefuMsgType.VOICE.equals(message.getMsgType())) { - JsonObject voice = new JsonObject(); - voice.addProperty("media_id", message.getMediaId()); - messageJson.add("voice", voice); - } - - if (WxConsts.KefuMsgType.VIDEO.equals(message.getMsgType())) { - JsonObject video = new JsonObject(); - video.addProperty("media_id", message.getMediaId()); - video.addProperty("thumb_media_id", message.getThumbMediaId()); - video.addProperty("title", message.getTitle()); - video.addProperty("description", message.getDescription()); - messageJson.add("video", video); - } - - if (WxConsts.KefuMsgType.MUSIC.equals(message.getMsgType())) { - JsonObject music = new JsonObject(); - music.addProperty("title", message.getTitle()); - music.addProperty("description", message.getDescription()); - music.addProperty("thumb_media_id", message.getThumbMediaId()); - music.addProperty("musicurl", message.getMusicUrl()); - music.addProperty("hqmusicurl", message.getHqMusicUrl()); - messageJson.add("music", music); - } - - if (WxConsts.KefuMsgType.NEWS.equals(message.getMsgType())) { - JsonObject newsJsonObject = new JsonObject(); - JsonArray articleJsonArray = new JsonArray(); - for (WxMpKefuMessage.WxArticle article : message.getArticles()) { - JsonObject articleJson = new JsonObject(); - articleJson.addProperty("title", article.getTitle()); - articleJson.addProperty("description", article.getDescription()); - articleJson.addProperty("url", article.getUrl()); - articleJson.addProperty("picurl", article.getPicUrl()); - articleJsonArray.add(articleJson); + switch (message.getMsgType()) { + case KefuMsgType.TEXT: + JsonObject text = new JsonObject(); + text.addProperty("content", message.getContent()); + messageJson.add("text", text); + break; + case KefuMsgType.IMAGE: + JsonObject image = new JsonObject(); + image.addProperty("media_id", message.getMediaId()); + messageJson.add("image", image); + break; + case KefuMsgType.VOICE: + JsonObject voice = new JsonObject(); + voice.addProperty("media_id", message.getMediaId()); + messageJson.add("voice", voice); + break; + case KefuMsgType.VIDEO: + JsonObject video = new JsonObject(); + video.addProperty("media_id", message.getMediaId()); + video.addProperty("thumb_media_id", message.getThumbMediaId()); + video.addProperty("title", message.getTitle()); + video.addProperty("description", message.getDescription()); + messageJson.add("video", video); + break; + case KefuMsgType.MUSIC: + JsonObject music = new JsonObject(); + music.addProperty("title", message.getTitle()); + music.addProperty("description", message.getDescription()); + music.addProperty("thumb_media_id", message.getThumbMediaId()); + music.addProperty("musicurl", message.getMusicUrl()); + music.addProperty("hqmusicurl", message.getHqMusicUrl()); + messageJson.add("music", music); + break; + case KefuMsgType.NEWS: + JsonObject newsJsonObject = new JsonObject(); + JsonArray articleJsonArray = new JsonArray(); + for (WxMpKefuMessage.WxArticle article : message.getArticles()) { + JsonObject articleJson = new JsonObject(); + articleJson.addProperty("title", article.getTitle()); + articleJson.addProperty("description", article.getDescription()); + articleJson.addProperty("url", article.getUrl()); + articleJson.addProperty("picurl", article.getPicUrl()); + articleJsonArray.add(articleJson); + } + newsJsonObject.add("articles", articleJsonArray); + messageJson.add("news", newsJsonObject); + break; + case KefuMsgType.MPNEWS: + JsonObject json = new JsonObject(); + json.addProperty("media_id", message.getMpNewsMediaId()); + messageJson.add("mpnews", json); + break; + case KefuMsgType.WXCARD: + JsonObject wxcard = new JsonObject(); + wxcard.addProperty("card_id", message.getCardId()); + messageJson.add("wxcard", wxcard); + break; + case KefuMsgType.MINIPROGRAMPAGE: + JsonObject miniProgramPage = new JsonObject(); + miniProgramPage.addProperty("title", message.getTitle()); + miniProgramPage.addProperty("appid", message.getMiniProgramAppId()); + miniProgramPage.addProperty("pagepath", message.getMiniProgramPagePath()); + miniProgramPage.addProperty("thumb_media_id", message.getThumbMediaId()); + messageJson.add("miniprogrampage", miniProgramPage); + break; + case KefuMsgType.MSGMENU: { + JsonObject msgMenu = new JsonObject(); + JsonArray array = new JsonArray(); + for (String s : message.getMsgMenuList()) { + JsonObject innerJson = new JsonObject(); + final String[] split = s.split(","); + innerJson.addProperty("id", split[0]); + innerJson.addProperty("content", split[1]); + array.add(innerJson); + } + msgMenu.addProperty("head_content", message.getHeadContent()); + msgMenu.add("list", array); + msgMenu.addProperty("tail_content", message.getTailContent()); + messageJson.add("msgmenu", msgMenu); + break; + } + default: { + throw new RuntimeException("非法消息类型,暂不支持"); } - newsJsonObject.add("articles", articleJsonArray); - messageJson.add("news", newsJsonObject); - } - - if (WxConsts.KefuMsgType.MPNEWS.equals(message.getMsgType())) { - JsonObject json = new JsonObject(); - json.addProperty("media_id", message.getMpNewsMediaId()); - messageJson.add("mpnews", json); - } - - if (WxConsts.KefuMsgType.WXCARD.equals(message.getMsgType())) { - JsonObject wxcard = new JsonObject(); - wxcard.addProperty("card_id", message.getCardId()); - messageJson.add("wxcard", wxcard); - } - - if (KefuMsgType.MINIPROGRAMPAGE.equals(message.getMsgType())) { - JsonObject miniProgramPage = new JsonObject(); - miniProgramPage.addProperty("title", message.getTitle()); - miniProgramPage.addProperty("appid", message.getMiniProgramAppId()); - miniProgramPage.addProperty("pagepath", message.getMiniProgramPagePath()); - miniProgramPage.addProperty("thumb_media_id", message.getThumbMediaId()); - messageJson.add("miniprogrampage", miniProgramPage); } if (StringUtils.isNotBlank(message.getKfAccount())) { diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessageTest.java index 4f983dde13..cf45873b51 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessageTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessageTest.java @@ -5,6 +5,8 @@ import org.testng.Assert; import org.testng.annotations.Test; +import static org.assertj.core.api.Assertions.assertThat; + @Test public class WxMpKefuMessageTest { @@ -141,7 +143,6 @@ public void testNewsBuild() { } public void testMiniProgramPageBuild() { - WxMpKefuMessage reply = WxMpKefuMessage.MINIPROGRAMPAGE() .toUser("OPENID") .title("title") @@ -154,4 +155,16 @@ public void testMiniProgramPageBuild() { "{\"touser\":\"OPENID\",\"msgtype\":\"miniprogrampage\",\"miniprogrampage\":{\"title\":\"title\",\"appid\":\"appid\",\"pagepath\":\"pagepath\",\"thumb_media_id\":\"thumb_media_id\"}}"); } + public void testMsgMenuBuild() { + WxMpKefuMessage reply = WxMpKefuMessage.MSGMENU() + .toUser("OPENID") + .msgMenuList("101,满意", "102,不满意") + .headContent("您对本次服务是否满意呢?") + .tailContent("欢迎再次光临") + .build(); + + assertThat(reply.toJson()) + .isEqualTo("{\"touser\":\"OPENID\",\"msgtype\":\"msgmenu\",\"msgmenu\":{\"head_content\":\"您对本次服务是否满意呢?\",\"list\":[{\"id\":\"101\",\"content\":\"满意\"},{\"id\":\"102\",\"content\":\"不满意\"}],\"tail_content\":\"欢迎再次光临\"}}"); + } + } From af9b3a4529ab9ce1b57a6eabd96d57a9058a2e7d Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 9 Jun 2019 21:15:42 +0800 Subject: [PATCH 20/74] =?UTF-8?q?#1039=20=E5=BE=AE=E4=BF=A1=E5=85=AC?= =?UTF-8?q?=E4=BC=97=E5=8F=B7=E6=8E=A5=E5=8F=A3=E5=9C=B0=E5=9D=80=E5=9F=9F?= =?UTF-8?q?=E5=90=8D=E9=83=A8=E5=88=86=E8=BF=9B=E8=A1=8C=E5=8F=AF=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=8C=96=20=E6=94=B9=E9=80=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/mp/api/WxMpConfigStorage.java | 11 +- .../mp/api/WxMpInMemoryConfigStorage.java | 6 + .../mp/api/impl/BaseWxMpServiceImpl.java | 18 +- .../mp/api/impl/WxMpAiOpenServiceImpl.java | 6 +- .../mp/api/impl/WxMpKefuServiceImpl.java | 12 +- .../mp/api/impl/WxMpMaterialServiceImpl.java | 4 +- .../mp/api/impl/WxMpQrcodeServiceImpl.java | 3 +- .../api/impl/WxMpServiceHttpClientImpl.java | 21 +- .../mp/api/impl/WxMpServiceJoddHttpImpl.java | 14 +- .../mp/api/impl/WxMpServiceOkHttpImpl.java | 17 +- .../api/impl/WxMpSubscribeMsgServiceImpl.java | 2 +- .../weixin/mp/bean/WxMpHostConfig.java | 56 +++ .../chanjar/weixin/mp/enums/WxMpApiUrl.java | 376 +++++++++--------- .../weixin/mp/util/json/WxMpGsonBuilder.java | 3 + .../api/impl/WxOpenInMemoryConfigStorage.java | 7 +- .../open/api/impl/WxOpenMpServiceImpl.java | 2 +- 16 files changed, 317 insertions(+), 241 deletions(-) create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpHostConfig.java diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java index 53e5fc6943..bd5476d473 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java @@ -1,12 +1,13 @@ package me.chanjar.weixin.mp.api; -import java.io.File; -import java.util.concurrent.locks.Lock; - import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.mp.bean.WxMpHostConfig; import me.chanjar.weixin.mp.enums.TicketType; +import java.io.File; +import java.util.concurrent.locks.Lock; + /** * 微信客户端配置存储. * @@ -96,4 +97,8 @@ public interface WxMpConfigStorage { */ boolean autoRefreshToken(); + /** + * 得到微信接口地址域名部分的自定义设置信息. + */ + WxMpHostConfig getHostConfig(); } 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 4f24b1671a..31eca6a4e2 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 @@ -8,6 +8,7 @@ import lombok.Data; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.mp.bean.WxMpHostConfig; import me.chanjar.weixin.mp.enums.TicketType; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; @@ -179,4 +180,9 @@ public boolean autoRefreshToken() { return true; } + @Override + public WxMpHostConfig getHostConfig() { + return null; + } + } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java index 28b69b98f7..fc467e99e9 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java @@ -157,13 +157,13 @@ public WxMpSemanticQueryResult semanticQuery(WxMpSemanticQuery semanticQuery) th @Override public String oauth2buildAuthorizationUrl(String redirectURI, String scope, String state) { - return String.format(CONNECT_OAUTH2_AUTHORIZE_URL.getUrl(), + return String.format(CONNECT_OAUTH2_AUTHORIZE_URL.getUrl(this.getWxMpConfigStorage()), this.getWxMpConfigStorage().getAppId(), URIUtil.encodeURIComponent(redirectURI), scope, StringUtils.trimToEmpty(state)); } @Override public String buildQrConnectUrl(String redirectURI, String scope, String state) { - return String.format(QRCONNECT_URL.getUrl(), this.getWxMpConfigStorage().getAppId(), + return String.format(QRCONNECT_URL.getUrl(this.getWxMpConfigStorage()), this.getWxMpConfigStorage().getAppId(), URIUtil.encodeURIComponent(redirectURI), scope, StringUtils.trimToEmpty(state)); } @@ -179,14 +179,14 @@ private WxMpOAuth2AccessToken getOAuth2AccessToken(String url) throws WxErrorExc @Override public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException { - String url = String.format(OAUTH2_ACCESS_TOKEN_URL.getUrl(), this.getWxMpConfigStorage().getAppId(), + String url = String.format(OAUTH2_ACCESS_TOKEN_URL.getUrl(this.getWxMpConfigStorage()), this.getWxMpConfigStorage().getAppId(), this.getWxMpConfigStorage().getSecret(), code); return this.getOAuth2AccessToken(url); } @Override public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException { - String url = String.format(OAUTH2_REFRESH_TOKEN_URL.getUrl(), this.getWxMpConfigStorage().getAppId(), refreshToken); + String url = String.format(OAUTH2_REFRESH_TOKEN_URL.getUrl(this.getWxMpConfigStorage()), this.getWxMpConfigStorage().getAppId(), refreshToken); return this.getOAuth2AccessToken(url); } @@ -196,7 +196,7 @@ public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken token, String lang) thro lang = "zh_CN"; } - String url = String.format(OAUTH2_USERINFO_URL.getUrl(), token.getAccessToken(), token.getOpenId(), lang); + String url = String.format(OAUTH2_USERINFO_URL.getUrl(this.getWxMpConfigStorage()), token.getAccessToken(), token.getOpenId(), lang); try { RequestExecutor executor = SimpleGetRequestExecutor.create(this); @@ -209,7 +209,7 @@ public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken token, String lang) thro @Override public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken token) { - String url = String.format(OAUTH2_VALIDATE_TOKEN_URL.getUrl(), token.getAccessToken(), token.getOpenId()); + String url = String.format(OAUTH2_VALIDATE_TOKEN_URL.getUrl(this.getWxMpConfigStorage()), token.getAccessToken(), token.getOpenId()); try { SimpleGetRequestExecutor.create(this).execute(url, null); @@ -252,7 +252,7 @@ public String get(String url, String queryParam) throws WxErrorException { @Override public String get(WxMpApiUrl url, String queryParam) throws WxErrorException { - return this.get(url.getUrl(), queryParam); + return this.get(url.getUrl(this.getWxMpConfigStorage()), queryParam); } @Override @@ -262,12 +262,12 @@ public String post(String url, String postData) throws WxErrorException { @Override public String post(WxMpApiUrl url, String postData) throws WxErrorException { - return this.post(url.getUrl(), postData); + return this.post(url.getUrl(this.getWxMpConfigStorage()), postData); } @Override public T execute(RequestExecutor executor, WxMpApiUrl url, E data) throws WxErrorException { - return this.execute(executor, url.getUrl(), data); + return this.execute(executor, url.getUrl(this.getWxMpConfigStorage()), data); } /** diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java index 119376d621..5ac3be31fd 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpAiOpenServiceImpl.java @@ -8,7 +8,6 @@ import me.chanjar.weixin.mp.api.WxMpAiOpenService; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.enums.AiLangType; -import me.chanjar.weixin.mp.enums.WxMpApiUrl; import me.chanjar.weixin.mp.util.requestexecuter.voice.VoiceUploadRequestExecutor; import java.io.File; @@ -34,7 +33,7 @@ public void uploadVoice(String voiceId, AiLangType lang, File voiceFile) throws } this.wxMpService.execute(VoiceUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), - String.format(VOICE_UPLOAD_URL.getUrl(), "mp3", voiceId, lang.getCode()), + String.format(VOICE_UPLOAD_URL.getUrl(this.wxMpService.getWxMpConfigStorage()), "mp3", voiceId, lang.getCode()), voiceFile); } @@ -46,7 +45,8 @@ public String recogniseVoice(String voiceId, AiLangType lang, File voiceFile) th @Override public String translate(AiLangType langFrom, AiLangType langTo, String content) throws WxErrorException { - String response = this.wxMpService.post(String.format(TRANSLATE_URL.getUrl(), langFrom.getCode(), langTo.getCode()), content); + String response = this.wxMpService.post(String.format(TRANSLATE_URL.getUrl(this.wxMpService.getWxMpConfigStorage()), + langFrom.getCode(), langTo.getCode()), content); WxError error = WxError.fromJson(response, WxType.MP); if (error.getErrorCode() != 0) { 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 4743cc247a..a131e3a9f3 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 @@ -13,7 +13,6 @@ 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 me.chanjar.weixin.mp.enums.WxMpApiUrl; import java.io.File; import java.util.Date; @@ -68,13 +67,14 @@ public boolean kfAccountInviteWorker(WxMpKfAccountRequest request) throws WxErro public boolean kfAccountUploadHeadImg(String kfAccount, File imgFile) throws WxErrorException { WxMediaUploadResult responseContent = this.wxMpService .execute(MediaUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), - String.format(KFACCOUNT_UPLOAD_HEAD_IMG.getUrl(), kfAccount), imgFile); + String.format(KFACCOUNT_UPLOAD_HEAD_IMG.getUrl(this.wxMpService.getWxMpConfigStorage()), kfAccount), imgFile); return responseContent != null; } @Override public boolean kfAccountDel(String kfAccount) throws WxErrorException { - String responseContent = this.wxMpService.get(String.format(KFACCOUNT_DEL.getUrl(), kfAccount), null); + String responseContent = this.wxMpService.get(String.format(KFACCOUNT_DEL.getUrl(this.wxMpService.getWxMpConfigStorage()), + kfAccount), null); return responseContent != null; } @@ -94,13 +94,15 @@ public boolean kfSessionClose(String openid, String kfAccount) throws WxErrorExc @Override public WxMpKfSessionGetResult kfSessionGet(String openid) throws WxErrorException { - String responseContent = this.wxMpService.get(String.format(KFSESSION_GET_SESSION.getUrl(), openid), null); + String responseContent = this.wxMpService.get(String.format(KFSESSION_GET_SESSION + .getUrl(this.wxMpService.getWxMpConfigStorage()), openid), null); return WxMpKfSessionGetResult.fromJson(responseContent); } @Override public WxMpKfSessionList kfSessionList(String kfAccount) throws WxErrorException { - String responseContent = this.wxMpService.get(String.format(KFSESSION_GET_SESSION_LIST.getUrl(), kfAccount), null); + String responseContent = this.wxMpService.get(String.format(KFSESSION_GET_SESSION_LIST + .getUrl(this.wxMpService.getWxMpConfigStorage()), kfAccount), null); return WxMpKfSessionList.fromJson(responseContent); } 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 3352b95e21..2ceec219f7 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 @@ -53,7 +53,7 @@ public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputS @Override public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException { - String url = String.format(MEDIA_UPLOAD_URL.getUrl(), mediaType); + String url = String.format(MEDIA_UPLOAD_URL.getUrl(this.wxMpService.getWxMpConfigStorage()), mediaType); return this.wxMpService.execute(MediaUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), url, file); } @@ -72,7 +72,7 @@ public WxMediaImgUploadResult mediaImgUpload(File file) throws WxErrorException @Override public WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMaterial material) throws WxErrorException { - String url = String.format(MATERIAL_ADD_URL.getUrl(), mediaType); + String url = String.format(MATERIAL_ADD_URL.getUrl(this.wxMpService.getWxMpConfigStorage()), mediaType); return this.wxMpService.execute(MaterialUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), url, material); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java index da4171fbb4..a654afb769 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java @@ -105,7 +105,8 @@ public File qrCodePicture(WxMpQrCodeTicket ticket) throws WxErrorException { @Override public String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErrorException { try { - String resultUrl = String.format(SHOW_QRCODE_WITH_TICKET.getUrl(), URLEncoder.encode(ticket, StandardCharsets.UTF_8.name())); + String resultUrl = String.format(SHOW_QRCODE_WITH_TICKET.getUrl(this.wxMpService.getWxMpConfigStorage()), + URLEncoder.encode(ticket, StandardCharsets.UTF_8.name())); if (needShortUrl) { return this.wxMpService.shortUrl(resultUrl); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java index 0c00793a0c..17aec251f7 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java @@ -8,7 +8,6 @@ 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.mp.enums.WxMpApiUrl; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; @@ -19,7 +18,7 @@ import java.io.IOException; import java.util.concurrent.locks.Lock; -import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.*; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.GET_ACCESS_TOKEN_URL; /** * apache http client方式实现. @@ -67,20 +66,20 @@ public void initHttp() { @Override public String getAccessToken(boolean forceRefresh) throws WxErrorException { - if (!this.getWxMpConfigStorage().isAccessTokenExpired() && !forceRefresh) { - return this.getWxMpConfigStorage().getAccessToken(); + final WxMpConfigStorage config = this.getWxMpConfigStorage(); + if (!config.isAccessTokenExpired() && !forceRefresh) { + return config.getAccessToken(); } - Lock lock = this.getWxMpConfigStorage().getAccessTokenLock(); + Lock lock = config.getAccessTokenLock(); lock.lock(); try { - String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(), - this.getWxMpConfigStorage().getAppId(), this.getWxMpConfigStorage().getSecret()); + String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(config), config.getAppId(), config.getSecret()); try { HttpGet httpGet = new HttpGet(url); if (this.getRequestHttpProxy() != null) { - RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build(); - httpGet.setConfig(config); + RequestConfig requestConfig = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build(); + httpGet.setConfig(requestConfig); } try (CloseableHttpResponse response = getRequestHttpClient().execute(httpGet)) { String resultContent = new BasicResponseHandler().handleResponse(response); @@ -89,8 +88,8 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { throw new WxErrorException(error); } WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); - this.getWxMpConfigStorage().updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); - return this.getWxMpConfigStorage().getAccessToken(); + config.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); + return config.getAccessToken(); } finally { httpGet.releaseConnection(); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java index 9b78f04cad..ee1074b508 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java @@ -51,15 +51,15 @@ public void initHttp() { @Override public String getAccessToken(boolean forceRefresh) throws WxErrorException { - if (!this.getWxMpConfigStorage().isAccessTokenExpired() && !forceRefresh) { - return this.getWxMpConfigStorage().getAccessToken(); + final WxMpConfigStorage config = this.getWxMpConfigStorage(); + if (!config.isAccessTokenExpired() && !forceRefresh) { + return config.getAccessToken(); } - Lock lock = this.getWxMpConfigStorage().getAccessTokenLock(); + Lock lock = config.getAccessTokenLock(); lock.lock(); try { - String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(), - this.getWxMpConfigStorage().getAppId(), this.getWxMpConfigStorage().getSecret()); + String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(config), config.getAppId(), config.getSecret()); HttpRequest request = HttpRequest.get(url); @@ -76,9 +76,9 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { throw new WxErrorException(error); } WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); - this.getWxMpConfigStorage().updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); + config.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); - return this.getWxMpConfigStorage().getAccessToken(); + return config.getAccessToken(); } finally { lock.unlock(); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java index f166d93c7f..f1c1193c12 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java @@ -7,13 +7,12 @@ import me.chanjar.weixin.common.util.http.HttpType; import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; import me.chanjar.weixin.mp.api.WxMpConfigStorage; -import me.chanjar.weixin.mp.enums.WxMpApiUrl; import okhttp3.*; import java.io.IOException; import java.util.concurrent.locks.Lock; -import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.*; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.GET_ACCESS_TOKEN_URL; /** * okhttp实现. @@ -41,15 +40,15 @@ public HttpType getRequestType() { @Override public String getAccessToken(boolean forceRefresh) throws WxErrorException { - if (!this.getWxMpConfigStorage().isAccessTokenExpired() && !forceRefresh) { - return this.getWxMpConfigStorage().getAccessToken(); + final WxMpConfigStorage config = this.getWxMpConfigStorage(); + if (!config.isAccessTokenExpired() && !forceRefresh) { + return config.getAccessToken(); } - Lock lock = this.getWxMpConfigStorage().getAccessTokenLock(); + Lock lock = config.getAccessTokenLock(); lock.lock(); try { - String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(), - this.getWxMpConfigStorage().getAppId(), this.getWxMpConfigStorage().getSecret()); + String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(config), config.getAppId(), config.getSecret()); Request request = new Request.Builder().url(url).get().build(); Response response = getRequestHttpClient().newCall(request).execute(); @@ -59,9 +58,9 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { throw new WxErrorException(error); } WxAccessToken accessToken = WxAccessToken.fromJson(resultContent); - this.getWxMpConfigStorage().updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); + config.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); - return this.getWxMpConfigStorage().getAccessToken(); + return config.getAccessToken(); } catch (IOException e) { throw new RuntimeException(e); } finally { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpSubscribeMsgServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpSubscribeMsgServiceImpl.java index fb6559ba13..b9c5d4fd3c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpSubscribeMsgServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpSubscribeMsgServiceImpl.java @@ -24,7 +24,7 @@ public class WxMpSubscribeMsgServiceImpl implements WxMpSubscribeMsgService { @Override public String subscribeMsgAuthorizationUrl(String redirectURI, int scene, String reserved) { WxMpConfigStorage storage = this.wxMpService.getWxMpConfigStorage(); - return String.format(SUBSCRIBE_MESSAGE_AUTHORIZE_URL.getUrl(), storage.getAppId(), scene, storage.getTemplateId(), + return String.format(SUBSCRIBE_MESSAGE_AUTHORIZE_URL.getUrl(storage), storage.getAppId(), scene, storage.getTemplateId(), URIUtil.encodeURIComponent(redirectURI), reserved); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpHostConfig.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpHostConfig.java new file mode 100644 index 0000000000..9fff434e1f --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpHostConfig.java @@ -0,0 +1,56 @@ +package me.chanjar.weixin.mp.bean; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 微信接口地址域名部分的自定义设置信息. + * + * @author Binary Wang + * @date 2019-06-09 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WxMpHostConfig { + public static final String API_DEFAULT_HOST_URL = "https://api.weixin.qq.com"; + public static final String MP_DEFAULT_HOST_URL = "https://mp.weixin.qq.com"; + public static final String OPEN_DEFAULT_HOST_URL = "https://open.weixin.qq.com"; + + /** + * 对应于:https://api.weixin.qq.com + */ + private String apiHost; + + /** + * 对应于:https://open.weixin.qq.com + */ + private String openHost; + /** + * 对应于:https://mp.weixin.qq.com + */ + private String mpHost; + + public static String buildUrl(WxMpHostConfig hostConfig, String prefix, String path) { + if (hostConfig == null) { + return prefix + path; + } + + if (hostConfig.getApiHost() != null && prefix.equals(API_DEFAULT_HOST_URL)) { + return hostConfig.getApiHost() + path; + } + + if (hostConfig.getMpHost() != null && prefix.equals(MP_DEFAULT_HOST_URL)) { + return hostConfig.getMpHost() + path; + } + + if (hostConfig.getOpenHost() != null && prefix.equals(OPEN_DEFAULT_HOST_URL)) { + return hostConfig.getOpenHost() + path; + } + + return prefix + path; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java index 2ab5fd7016..e25e251e1c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java @@ -1,6 +1,9 @@ package me.chanjar.weixin.mp.enums; import lombok.AllArgsConstructor; +import me.chanjar.weixin.mp.api.WxMpConfigStorage; + +import static me.chanjar.weixin.mp.bean.WxMpHostConfig.*; /** *
@@ -11,127 +14,125 @@
  * @author Binary Wang
  */
 public interface WxMpApiUrl {
-  String WX_API_BASE_URL = "https://api.weixin.qq.com";
-  String WX_MP_BASE_URL = "https://mp.weixin.qq.com";
-  String WX_OPEN_BASE_URL = "https://open.weixin.qq.com";
 
   /**
    * 得到api完整地址.
    *
+   * @param config 微信公众号配置
    * @return api地址
    */
-  String getUrl();
+  String getUrl(WxMpConfigStorage config);
 
   @AllArgsConstructor
   enum Device implements WxMpApiUrl {
     /**
      * get_bind_device.
      */
-    DEVICE_GET_BIND_DEVICE(WX_API_BASE_URL, "/device/get_bind_device"),
+    DEVICE_GET_BIND_DEVICE(API_DEFAULT_HOST_URL, "/device/get_bind_device"),
     /**
      * get_openid.
      */
-    DEVICE_GET_OPENID(WX_API_BASE_URL, "/device/get_openid"),
+    DEVICE_GET_OPENID(API_DEFAULT_HOST_URL, "/device/get_openid"),
     /**
      * compel_unbind.
      */
-    DEVICE_COMPEL_UNBIND(WX_API_BASE_URL, "/device/compel_unbind?"),
+    DEVICE_COMPEL_UNBIND(API_DEFAULT_HOST_URL, "/device/compel_unbind?"),
     /**
      * unbind.
      */
-    DEVICE_UNBIND(WX_API_BASE_URL, "/device/unbind?"),
+    DEVICE_UNBIND(API_DEFAULT_HOST_URL, "/device/unbind?"),
     /**
      * compel_bind.
      */
-    DEVICE_COMPEL_BIND(WX_API_BASE_URL, "/device/compel_bind"),
+    DEVICE_COMPEL_BIND(API_DEFAULT_HOST_URL, "/device/compel_bind"),
     /**
      * bind.
      */
-    DEVICE_BIND(WX_API_BASE_URL, "/device/bind"),
+    DEVICE_BIND(API_DEFAULT_HOST_URL, "/device/bind"),
     /**
      * authorize_device.
      */
-    DEVICE_AUTHORIZE_DEVICE(WX_API_BASE_URL, "/device/authorize_device"),
+    DEVICE_AUTHORIZE_DEVICE(API_DEFAULT_HOST_URL, "/device/authorize_device"),
     /**
      * getqrcode.
      */
-    DEVICE_GETQRCODE(WX_API_BASE_URL, "/device/getqrcode"),
+    DEVICE_GETQRCODE(API_DEFAULT_HOST_URL, "/device/getqrcode"),
     /**
      * transmsg.
      */
-    DEVICE_TRANSMSG(WX_API_BASE_URL, "/device/transmsg");
+    DEVICE_TRANSMSG(API_DEFAULT_HOST_URL, "/device/transmsg");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
-  }
 
+  }
 
   @AllArgsConstructor
   enum Other implements WxMpApiUrl {
     /**
      * 获取access_token.
      */
-    GET_ACCESS_TOKEN_URL(WX_API_BASE_URL, "/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"),
+    GET_ACCESS_TOKEN_URL(API_DEFAULT_HOST_URL, "/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"),
     /**
      * 获得各种类型的ticket.
      */
-    GET_TICKET_URL(WX_API_BASE_URL, "/cgi-bin/ticket/getticket?type="),
+    GET_TICKET_URL(API_DEFAULT_HOST_URL, "/cgi-bin/ticket/getticket?type="),
     /**
      * 长链接转短链接接口.
      */
-    SHORTURL_API_URL(WX_API_BASE_URL, "/cgi-bin/shorturl"),
+    SHORTURL_API_URL(API_DEFAULT_HOST_URL, "/cgi-bin/shorturl"),
     /**
      * 语义查询接口.
      */
-    SEMANTIC_SEMPROXY_SEARCH_URL(WX_API_BASE_URL, "/semantic/semproxy/search"),
+    SEMANTIC_SEMPROXY_SEARCH_URL(API_DEFAULT_HOST_URL, "/semantic/semproxy/search"),
     /**
      * 用code换取oauth2的access token.
      */
-    OAUTH2_ACCESS_TOKEN_URL(WX_API_BASE_URL, "/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code"),
+    OAUTH2_ACCESS_TOKEN_URL(API_DEFAULT_HOST_URL, "/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code"),
     /**
      * 刷新oauth2的access token.
      */
-    OAUTH2_REFRESH_TOKEN_URL(WX_API_BASE_URL, "/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s"),
+    OAUTH2_REFRESH_TOKEN_URL(API_DEFAULT_HOST_URL, "/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s"),
     /**
      * 用oauth2获取用户信息.
      */
-    OAUTH2_USERINFO_URL(WX_API_BASE_URL, "/sns/userinfo?access_token=%s&openid=%s&lang=%s"),
+    OAUTH2_USERINFO_URL(API_DEFAULT_HOST_URL, "/sns/userinfo?access_token=%s&openid=%s&lang=%s"),
     /**
      * 验证oauth2的access token是否有效.
      */
-    OAUTH2_VALIDATE_TOKEN_URL(WX_API_BASE_URL, "/sns/auth?access_token=%s&openid=%s"),
+    OAUTH2_VALIDATE_TOKEN_URL(API_DEFAULT_HOST_URL, "/sns/auth?access_token=%s&openid=%s"),
     /**
      * 获取微信服务器IP地址.
      */
-    GET_CALLBACK_IP_URL(WX_API_BASE_URL, "/cgi-bin/getcallbackip"),
+    GET_CALLBACK_IP_URL(API_DEFAULT_HOST_URL, "/cgi-bin/getcallbackip"),
     /**
      * 第三方使用网站应用授权登录的url.
      */
-    QRCONNECT_URL(WX_OPEN_BASE_URL, "/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect"),
+    QRCONNECT_URL(OPEN_DEFAULT_HOST_URL, "/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect"),
     /**
      * oauth2授权的url连接.
      */
-    CONNECT_OAUTH2_AUTHORIZE_URL(WX_OPEN_BASE_URL, "/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s&connect_redirect=1#wechat_redirect"),
+    CONNECT_OAUTH2_AUTHORIZE_URL(OPEN_DEFAULT_HOST_URL, "/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s&connect_redirect=1#wechat_redirect"),
     /**
      * 获取公众号的自动回复规则.
      */
-    GET_CURRENT_AUTOREPLY_INFO_URL(WX_API_BASE_URL, "/cgi-bin/get_current_autoreply_info"),
+    GET_CURRENT_AUTOREPLY_INFO_URL(API_DEFAULT_HOST_URL, "/cgi-bin/get_current_autoreply_info"),
     /**
      * 公众号调用或第三方平台帮公众号调用对公众号的所有api调用(包括第三方帮其调用)次数进行清零.
      */
-    CLEAR_QUOTA_URL(WX_API_BASE_URL, "/cgi-bin/clear_quota");
+    CLEAR_QUOTA_URL(API_DEFAULT_HOST_URL, "/cgi-bin/clear_quota");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -140,26 +141,26 @@ enum Marketing implements WxMpApiUrl {
     /**
      * sets add.
      */
-    USER_ACTION_SETS_ADD(WX_API_BASE_URL, "/marketing/user_action_sets/add?version=v1.0"),
+    USER_ACTION_SETS_ADD(API_DEFAULT_HOST_URL, "/marketing/user_action_sets/add?version=v1.0"),
     /**
      * get.
      */
-    USER_ACTION_SETS_GET(WX_API_BASE_URL, "/marketing/user_action_sets/get"),
+    USER_ACTION_SETS_GET(API_DEFAULT_HOST_URL, "/marketing/user_action_sets/get"),
     /**
      * add.
      */
-    USER_ACTIONS_ADD(WX_API_BASE_URL, "/marketing/user_actions/add?version=v1.0"),
+    USER_ACTIONS_ADD(API_DEFAULT_HOST_URL, "/marketing/user_actions/add?version=v1.0"),
     /**
      * get.
      */
-    WECHAT_AD_LEADS_GET(WX_API_BASE_URL, "/marketing/wechat_ad_leads/get");
+    WECHAT_AD_LEADS_GET(API_DEFAULT_HOST_URL, "/marketing/wechat_ad_leads/get");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -168,38 +169,38 @@ enum Menu implements WxMpApiUrl {
     /**
      * get_current_selfmenu_info.
      */
-    GET_CURRENT_SELFMENU_INFO(WX_API_BASE_URL, "/cgi-bin/get_current_selfmenu_info"),
+    GET_CURRENT_SELFMENU_INFO(API_DEFAULT_HOST_URL, "/cgi-bin/get_current_selfmenu_info"),
     /**
      * trymatch.
      */
-    MENU_TRYMATCH(WX_API_BASE_URL, "/cgi-bin/menu/trymatch"),
+    MENU_TRYMATCH(API_DEFAULT_HOST_URL, "/cgi-bin/menu/trymatch"),
     /**
      * get.
      */
-    MENU_GET(WX_API_BASE_URL, "/cgi-bin/menu/get"),
+    MENU_GET(API_DEFAULT_HOST_URL, "/cgi-bin/menu/get"),
     /**
      * delconditional.
      */
-    MENU_DELCONDITIONAL(WX_API_BASE_URL, "/cgi-bin/menu/delconditional"),
+    MENU_DELCONDITIONAL(API_DEFAULT_HOST_URL, "/cgi-bin/menu/delconditional"),
     /**
      * delete.
      */
-    MENU_DELETE(WX_API_BASE_URL, "/cgi-bin/menu/delete"),
+    MENU_DELETE(API_DEFAULT_HOST_URL, "/cgi-bin/menu/delete"),
     /**
      * create.
      */
-    MENU_CREATE(WX_API_BASE_URL, "/cgi-bin/menu/create"),
+    MENU_CREATE(API_DEFAULT_HOST_URL, "/cgi-bin/menu/create"),
     /**
      * addconditional.
      */
-    MENU_ADDCONDITIONAL(WX_API_BASE_URL, "/cgi-bin/menu/addconditional");
+    MENU_ADDCONDITIONAL(API_DEFAULT_HOST_URL, "/cgi-bin/menu/addconditional");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -209,22 +210,22 @@ enum Qrcode implements WxMpApiUrl {
     /**
      * create.
      */
-    QRCODE_CREATE(WX_API_BASE_URL, "/cgi-bin/qrcode/create"),
+    QRCODE_CREATE(API_DEFAULT_HOST_URL, "/cgi-bin/qrcode/create"),
     /**
      * showqrcode.
      */
-    SHOW_QRCODE(WX_MP_BASE_URL, "/cgi-bin/showqrcode"),
+    SHOW_QRCODE(MP_DEFAULT_HOST_URL, "/cgi-bin/showqrcode"),
     /**
      * showqrcode.
      */
-    SHOW_QRCODE_WITH_TICKET(WX_MP_BASE_URL, "/cgi-bin/showqrcode?ticket=%s");
+    SHOW_QRCODE_WITH_TICKET(MP_DEFAULT_HOST_URL, "/cgi-bin/showqrcode?ticket=%s");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -233,27 +234,26 @@ enum ShakeAround implements WxMpApiUrl {
     /**
      * getshakeinfo.
      */
-    SHAKEAROUND_USER_GETSHAKEINFO(WX_API_BASE_URL, "/shakearound/user/getshakeinfo"),
+    SHAKEAROUND_USER_GETSHAKEINFO(API_DEFAULT_HOST_URL, "/shakearound/user/getshakeinfo"),
     /**
      * add.
      */
-    SHAKEAROUND_PAGE_ADD(WX_API_BASE_URL, "/shakearound/page/add"),
+    SHAKEAROUND_PAGE_ADD(API_DEFAULT_HOST_URL, "/shakearound/page/add"),
     /**
      * bindpage.
      */
-    SHAKEAROUND_DEVICE_BINDPAGE(WX_API_BASE_URL, "/shakearound/device/bindpage"),
+    SHAKEAROUND_DEVICE_BINDPAGE(API_DEFAULT_HOST_URL, "/shakearound/device/bindpage"),
     /**
      * search.
      */
-    SHAKEAROUND_RELATION_SEARCH(WX_API_BASE_URL, "/shakearound/relation/search");
-
+    SHAKEAROUND_RELATION_SEARCH(API_DEFAULT_HOST_URL, "/shakearound/relation/search");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -262,18 +262,18 @@ enum SubscribeMsg implements WxMpApiUrl {
     /**
      * subscribemsg.
      */
-    SUBSCRIBE_MESSAGE_AUTHORIZE_URL(WX_MP_BASE_URL, "/mp/subscribemsg?action=get_confirm&appid=%s&scene=%d&template_id=%s&redirect_url=%s&reserved=%s#wechat_redirect"),
+    SUBSCRIBE_MESSAGE_AUTHORIZE_URL(MP_DEFAULT_HOST_URL, "/mp/subscribemsg?action=get_confirm&appid=%s&scene=%d&template_id=%s&redirect_url=%s&reserved=%s#wechat_redirect"),
     /**
      * subscribe.
      */
-    SEND_MESSAGE_URL(WX_API_BASE_URL, "/cgi-bin/message/template/subscribe");
+    SEND_MESSAGE_URL(API_DEFAULT_HOST_URL, "/cgi-bin/message/template/subscribe");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -282,34 +282,34 @@ enum TemplateMsg implements WxMpApiUrl {
     /**
      * send.
      */
-    MESSAGE_TEMPLATE_SEND(WX_API_BASE_URL, "/cgi-bin/message/template/send"),
+    MESSAGE_TEMPLATE_SEND(API_DEFAULT_HOST_URL, "/cgi-bin/message/template/send"),
     /**
      * api_set_industry.
      */
-    TEMPLATE_API_SET_INDUSTRY(WX_API_BASE_URL, "/cgi-bin/template/api_set_industry"),
+    TEMPLATE_API_SET_INDUSTRY(API_DEFAULT_HOST_URL, "/cgi-bin/template/api_set_industry"),
     /**
      * get_industry.
      */
-    TEMPLATE_GET_INDUSTRY(WX_API_BASE_URL, "/cgi-bin/template/get_industry"),
+    TEMPLATE_GET_INDUSTRY(API_DEFAULT_HOST_URL, "/cgi-bin/template/get_industry"),
     /**
      * api_add_template.
      */
-    TEMPLATE_API_ADD_TEMPLATE(WX_API_BASE_URL, "/cgi-bin/template/api_add_template"),
+    TEMPLATE_API_ADD_TEMPLATE(API_DEFAULT_HOST_URL, "/cgi-bin/template/api_add_template"),
     /**
      * get_all_private_template.
      */
-    TEMPLATE_GET_ALL_PRIVATE_TEMPLATE(WX_API_BASE_URL, "/cgi-bin/template/get_all_private_template"),
+    TEMPLATE_GET_ALL_PRIVATE_TEMPLATE(API_DEFAULT_HOST_URL, "/cgi-bin/template/get_all_private_template"),
     /**
      * del_private_template.
      */
-    TEMPLATE_DEL_PRIVATE_TEMPLATE(WX_API_BASE_URL, "/cgi-bin/template/del_private_template");
+    TEMPLATE_DEL_PRIVATE_TEMPLATE(API_DEFAULT_HOST_URL, "/cgi-bin/template/del_private_template");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -318,22 +318,22 @@ enum UserBlacklist implements WxMpApiUrl {
     /**
      * getblacklist.
      */
-    GETBLACKLIST(WX_API_BASE_URL, "/cgi-bin/tags/members/getblacklist"),
+    GETBLACKLIST(API_DEFAULT_HOST_URL, "/cgi-bin/tags/members/getblacklist"),
     /**
      * batchblacklist.
      */
-    BATCHBLACKLIST(WX_API_BASE_URL, "/cgi-bin/tags/members/batchblacklist"),
+    BATCHBLACKLIST(API_DEFAULT_HOST_URL, "/cgi-bin/tags/members/batchblacklist"),
     /**
      * batchunblacklist.
      */
-    BATCHUNBLACKLIST(WX_API_BASE_URL, "/cgi-bin/tags/members/batchunblacklist");
+    BATCHUNBLACKLIST(API_DEFAULT_HOST_URL, "/cgi-bin/tags/members/batchunblacklist");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -342,42 +342,42 @@ enum UserTag implements WxMpApiUrl {
     /**
      * create.
      */
-    TAGS_CREATE(WX_API_BASE_URL, "/cgi-bin/tags/create"),
+    TAGS_CREATE(API_DEFAULT_HOST_URL, "/cgi-bin/tags/create"),
     /**
      * get.
      */
-    TAGS_GET(WX_API_BASE_URL, "/cgi-bin/tags/get"),
+    TAGS_GET(API_DEFAULT_HOST_URL, "/cgi-bin/tags/get"),
     /**
      * update.
      */
-    TAGS_UPDATE(WX_API_BASE_URL, "/cgi-bin/tags/update"),
+    TAGS_UPDATE(API_DEFAULT_HOST_URL, "/cgi-bin/tags/update"),
     /**
      * delete.
      */
-    TAGS_DELETE(WX_API_BASE_URL, "/cgi-bin/tags/delete"),
+    TAGS_DELETE(API_DEFAULT_HOST_URL, "/cgi-bin/tags/delete"),
     /**
      * get.
      */
-    TAG_GET(WX_API_BASE_URL, "/cgi-bin/user/tag/get"),
+    TAG_GET(API_DEFAULT_HOST_URL, "/cgi-bin/user/tag/get"),
     /**
      * batchtagging.
      */
-    TAGS_MEMBERS_BATCHTAGGING(WX_API_BASE_URL, "/cgi-bin/tags/members/batchtagging"),
+    TAGS_MEMBERS_BATCHTAGGING(API_DEFAULT_HOST_URL, "/cgi-bin/tags/members/batchtagging"),
     /**
      * batchuntagging.
      */
-    TAGS_MEMBERS_BATCHUNTAGGING(WX_API_BASE_URL, "/cgi-bin/tags/members/batchuntagging"),
+    TAGS_MEMBERS_BATCHUNTAGGING(API_DEFAULT_HOST_URL, "/cgi-bin/tags/members/batchuntagging"),
     /**
      * getidlist.
      */
-    TAGS_GETIDLIST(WX_API_BASE_URL, "/cgi-bin/tags/getidlist");
+    TAGS_GETIDLIST(API_DEFAULT_HOST_URL, "/cgi-bin/tags/getidlist");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -386,14 +386,14 @@ enum Wifi implements WxMpApiUrl {
     /**
      * list.
      */
-    BIZWIFI_SHOP_LIST(WX_API_BASE_URL, "/bizwifi/shop/list");
+    BIZWIFI_SHOP_LIST(API_DEFAULT_HOST_URL, "/bizwifi/shop/list");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -402,22 +402,22 @@ enum AiOpen implements WxMpApiUrl {
     /**
      * translatecontent.
      */
-    TRANSLATE_URL(WX_API_BASE_URL, "/cgi-bin/media/voice/translatecontent?lfrom=%s<o=%s"),
+    TRANSLATE_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/voice/translatecontent?lfrom=%s<o=%s"),
     /**
      * addvoicetorecofortext.
      */
-    VOICE_UPLOAD_URL(WX_API_BASE_URL, "/cgi-bin/media/voice/addvoicetorecofortext?format=%s&voice_id=%s&lang=%s"),
+    VOICE_UPLOAD_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/voice/addvoicetorecofortext?format=%s&voice_id=%s&lang=%s"),
     /**
      * queryrecoresultfortext.
      */
-    VOICE_QUERY_RESULT_URL(WX_API_BASE_URL, "/cgi-bin/media/voice/queryrecoresultfortext");
+    VOICE_QUERY_RESULT_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/voice/queryrecoresultfortext");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -426,58 +426,58 @@ enum Card implements WxMpApiUrl {
     /**
      * create.
      */
-    CARD_CREATE(WX_API_BASE_URL, "/card/create"),
+    CARD_CREATE(API_DEFAULT_HOST_URL, "/card/create"),
     /**
      * get.
      */
-    CARD_GET(WX_API_BASE_URL, "/card/get"),
+    CARD_GET(API_DEFAULT_HOST_URL, "/card/get"),
     /**
      * wx_card.
      */
-    CARD_GET_TICKET(WX_API_BASE_URL, "/cgi-bin/ticket/getticket?type=wx_card"),
+    CARD_GET_TICKET(API_DEFAULT_HOST_URL, "/cgi-bin/ticket/getticket?type=wx_card"),
     /**
      * decrypt.
      */
-    CARD_CODE_DECRYPT(WX_API_BASE_URL, "/card/code/decrypt"),
+    CARD_CODE_DECRYPT(API_DEFAULT_HOST_URL, "/card/code/decrypt"),
     /**
      * get.
      */
-    CARD_CODE_GET(WX_API_BASE_URL, "/card/code/get"),
+    CARD_CODE_GET(API_DEFAULT_HOST_URL, "/card/code/get"),
     /**
      * consume.
      */
-    CARD_CODE_CONSUME(WX_API_BASE_URL, "/card/code/consume"),
+    CARD_CODE_CONSUME(API_DEFAULT_HOST_URL, "/card/code/consume"),
     /**
      * mark.
      */
-    CARD_CODE_MARK(WX_API_BASE_URL, "/card/code/mark"),
+    CARD_CODE_MARK(API_DEFAULT_HOST_URL, "/card/code/mark"),
     /**
      * set.
      */
-    CARD_TEST_WHITELIST(WX_API_BASE_URL, "/card/testwhitelist/set"),
+    CARD_TEST_WHITELIST(API_DEFAULT_HOST_URL, "/card/testwhitelist/set"),
     /**
      * create.
      */
-    CARD_QRCODE_CREATE(WX_API_BASE_URL, "/card/qrcode/create"),
+    CARD_QRCODE_CREATE(API_DEFAULT_HOST_URL, "/card/qrcode/create"),
     /**
      * create.
      */
-    CARD_LANDING_PAGE_CREATE(WX_API_BASE_URL, "/card/landingpage/create"),
+    CARD_LANDING_PAGE_CREATE(API_DEFAULT_HOST_URL, "/card/landingpage/create"),
     /**
      * 将用户的卡券设置为失效状态.
      */
-    CARD_CODE_UNAVAILABLE(WX_API_BASE_URL, "/card/code/unavailable"),
+    CARD_CODE_UNAVAILABLE(API_DEFAULT_HOST_URL, "/card/code/unavailable"),
     /**
      * 卡券删除.
      */
-    CARD_DELETE(WX_API_BASE_URL, "/card/delete");
+    CARD_DELETE(API_DEFAULT_HOST_URL, "/card/delete");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -486,78 +486,78 @@ enum DataCube implements WxMpApiUrl {
     /**
      * getusersummary.
      */
-    GET_USER_SUMMARY(WX_API_BASE_URL, "/datacube/getusersummary"),
+    GET_USER_SUMMARY(API_DEFAULT_HOST_URL, "/datacube/getusersummary"),
     /**
      * getusercumulate.
      */
-    GET_USER_CUMULATE(WX_API_BASE_URL, "/datacube/getusercumulate"),
+    GET_USER_CUMULATE(API_DEFAULT_HOST_URL, "/datacube/getusercumulate"),
     /**
      * getarticlesummary.
      */
-    GET_ARTICLE_SUMMARY(WX_API_BASE_URL, "/datacube/getarticlesummary"),
+    GET_ARTICLE_SUMMARY(API_DEFAULT_HOST_URL, "/datacube/getarticlesummary"),
     /**
      * getarticletotal.
      */
-    GET_ARTICLE_TOTAL(WX_API_BASE_URL, "/datacube/getarticletotal"),
+    GET_ARTICLE_TOTAL(API_DEFAULT_HOST_URL, "/datacube/getarticletotal"),
     /**
      * getuserread.
      */
-    GET_USER_READ(WX_API_BASE_URL, "/datacube/getuserread"),
+    GET_USER_READ(API_DEFAULT_HOST_URL, "/datacube/getuserread"),
     /**
      * getuserreadhour.
      */
-    GET_USER_READ_HOUR(WX_API_BASE_URL, "/datacube/getuserreadhour"),
+    GET_USER_READ_HOUR(API_DEFAULT_HOST_URL, "/datacube/getuserreadhour"),
     /**
      * getusershare.
      */
-    GET_USER_SHARE(WX_API_BASE_URL, "/datacube/getusershare"),
+    GET_USER_SHARE(API_DEFAULT_HOST_URL, "/datacube/getusershare"),
     /**
      * getusersharehour.
      */
-    GET_USER_SHARE_HOUR(WX_API_BASE_URL, "/datacube/getusersharehour"),
+    GET_USER_SHARE_HOUR(API_DEFAULT_HOST_URL, "/datacube/getusersharehour"),
     /**
      * getupstreammsg.
      */
-    GET_UPSTREAM_MSG(WX_API_BASE_URL, "/datacube/getupstreammsg"),
+    GET_UPSTREAM_MSG(API_DEFAULT_HOST_URL, "/datacube/getupstreammsg"),
     /**
      * getupstreammsghour.
      */
-    GET_UPSTREAM_MSG_HOUR(WX_API_BASE_URL, "/datacube/getupstreammsghour"),
+    GET_UPSTREAM_MSG_HOUR(API_DEFAULT_HOST_URL, "/datacube/getupstreammsghour"),
     /**
      * getupstreammsgweek.
      */
-    GET_UPSTREAM_MSG_WEEK(WX_API_BASE_URL, "/datacube/getupstreammsgweek"),
+    GET_UPSTREAM_MSG_WEEK(API_DEFAULT_HOST_URL, "/datacube/getupstreammsgweek"),
     /**
      * getupstreammsgmonth.
      */
-    GET_UPSTREAM_MSG_MONTH(WX_API_BASE_URL, "/datacube/getupstreammsgmonth"),
+    GET_UPSTREAM_MSG_MONTH(API_DEFAULT_HOST_URL, "/datacube/getupstreammsgmonth"),
     /**
      * getupstreammsgdist.
      */
-    GET_UPSTREAM_MSG_DIST(WX_API_BASE_URL, "/datacube/getupstreammsgdist"),
+    GET_UPSTREAM_MSG_DIST(API_DEFAULT_HOST_URL, "/datacube/getupstreammsgdist"),
     /**
      * getupstreammsgdistweek.
      */
-    GET_UPSTREAM_MSG_DIST_WEEK(WX_API_BASE_URL, "/datacube/getupstreammsgdistweek"),
+    GET_UPSTREAM_MSG_DIST_WEEK(API_DEFAULT_HOST_URL, "/datacube/getupstreammsgdistweek"),
     /**
      * getupstreammsgdistmonth.
      */
-    GET_UPSTREAM_MSG_DIST_MONTH(WX_API_BASE_URL, "/datacube/getupstreammsgdistmonth"),
+    GET_UPSTREAM_MSG_DIST_MONTH(API_DEFAULT_HOST_URL, "/datacube/getupstreammsgdistmonth"),
     /**
      * getinterfacesummary.
      */
-    GET_INTERFACE_SUMMARY(WX_API_BASE_URL, "/datacube/getinterfacesummary"),
+    GET_INTERFACE_SUMMARY(API_DEFAULT_HOST_URL, "/datacube/getinterfacesummary"),
     /**
      * getinterfacesummaryhour.
      */
-    GET_INTERFACE_SUMMARY_HOUR(WX_API_BASE_URL, "/datacube/getinterfacesummaryhour");
+    GET_INTERFACE_SUMMARY_HOUR(API_DEFAULT_HOST_URL, "/datacube/getinterfacesummaryhour");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -566,70 +566,70 @@ enum Kefu implements WxMpApiUrl {
     /**
      * send.
      */
-    MESSAGE_CUSTOM_SEND(WX_API_BASE_URL, "/cgi-bin/message/custom/send"),
+    MESSAGE_CUSTOM_SEND(API_DEFAULT_HOST_URL, "/cgi-bin/message/custom/send"),
     /**
      * getkflist.
      */
-    GET_KF_LIST(WX_API_BASE_URL, "/cgi-bin/customservice/getkflist"),
+    GET_KF_LIST(API_DEFAULT_HOST_URL, "/cgi-bin/customservice/getkflist"),
     /**
      * getonlinekflist.
      */
-    GET_ONLINE_KF_LIST(WX_API_BASE_URL, "/cgi-bin/customservice/getonlinekflist"),
+    GET_ONLINE_KF_LIST(API_DEFAULT_HOST_URL, "/cgi-bin/customservice/getonlinekflist"),
     /**
      * add.
      */
-    KFACCOUNT_ADD(WX_API_BASE_URL, "/customservice/kfaccount/add"),
+    KFACCOUNT_ADD(API_DEFAULT_HOST_URL, "/customservice/kfaccount/add"),
     /**
      * update.
      */
-    KFACCOUNT_UPDATE(WX_API_BASE_URL, "/customservice/kfaccount/update"),
+    KFACCOUNT_UPDATE(API_DEFAULT_HOST_URL, "/customservice/kfaccount/update"),
     /**
      * inviteworker.
      */
-    KFACCOUNT_INVITE_WORKER(WX_API_BASE_URL, "/customservice/kfaccount/inviteworker"),
+    KFACCOUNT_INVITE_WORKER(API_DEFAULT_HOST_URL, "/customservice/kfaccount/inviteworker"),
     /**
      * uploadheadimg.
      */
-    KFACCOUNT_UPLOAD_HEAD_IMG(WX_API_BASE_URL, "/customservice/kfaccount/uploadheadimg?kf_account=%s"),
+    KFACCOUNT_UPLOAD_HEAD_IMG(API_DEFAULT_HOST_URL, "/customservice/kfaccount/uploadheadimg?kf_account=%s"),
     /**
      * del kfaccount.
      */
-    KFACCOUNT_DEL(WX_API_BASE_URL, "/customservice/kfaccount/del?kf_account=%s"),
+    KFACCOUNT_DEL(API_DEFAULT_HOST_URL, "/customservice/kfaccount/del?kf_account=%s"),
     /**
      * create.
      */
-    KFSESSION_CREATE(WX_API_BASE_URL, "/customservice/kfsession/create"),
+    KFSESSION_CREATE(API_DEFAULT_HOST_URL, "/customservice/kfsession/create"),
     /**
      * close.
      */
-    KFSESSION_CLOSE(WX_API_BASE_URL, "/customservice/kfsession/close"),
+    KFSESSION_CLOSE(API_DEFAULT_HOST_URL, "/customservice/kfsession/close"),
     /**
      * getsession.
      */
-    KFSESSION_GET_SESSION(WX_API_BASE_URL, "/customservice/kfsession/getsession?openid=%s"),
+    KFSESSION_GET_SESSION(API_DEFAULT_HOST_URL, "/customservice/kfsession/getsession?openid=%s"),
     /**
      * getsessionlist.
      */
-    KFSESSION_GET_SESSION_LIST(WX_API_BASE_URL, "/customservice/kfsession/getsessionlist?kf_account=%s"),
+    KFSESSION_GET_SESSION_LIST(API_DEFAULT_HOST_URL, "/customservice/kfsession/getsessionlist?kf_account=%s"),
     /**
      * getwaitcase.
      */
-    KFSESSION_GET_WAIT_CASE(WX_API_BASE_URL, "/customservice/kfsession/getwaitcase"),
+    KFSESSION_GET_WAIT_CASE(API_DEFAULT_HOST_URL, "/customservice/kfsession/getwaitcase"),
     /**
      * getmsglist.
      */
-    MSG_RECORD_LIST(WX_API_BASE_URL, "/customservice/msgrecord/getmsglist"),
+    MSG_RECORD_LIST(API_DEFAULT_HOST_URL, "/customservice/msgrecord/getmsglist"),
     /**
      * typing.
      */
-    CUSTOM_TYPING(WX_API_BASE_URL, "/cgi-bin/message/custom/typing");
+    CUSTOM_TYPING(API_DEFAULT_HOST_URL, "/cgi-bin/message/custom/typing");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -638,34 +638,34 @@ enum MassMessage implements WxMpApiUrl {
     /**
      * 上传群发用的图文消息.
      */
-    MEDIA_UPLOAD_NEWS_URL(WX_API_BASE_URL, "/cgi-bin/media/uploadnews"),
+    MEDIA_UPLOAD_NEWS_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/uploadnews"),
     /**
      * 上传群发用的视频.
      */
-    MEDIA_UPLOAD_VIDEO_URL(WX_API_BASE_URL, "/cgi-bin/media/uploadvideo"),
+    MEDIA_UPLOAD_VIDEO_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/uploadvideo"),
     /**
      * 分组群发消息.
      */
-    MESSAGE_MASS_SENDALL_URL(WX_API_BASE_URL, "/cgi-bin/message/mass/sendall"),
+    MESSAGE_MASS_SENDALL_URL(API_DEFAULT_HOST_URL, "/cgi-bin/message/mass/sendall"),
     /**
      * 按openId列表群发消息.
      */
-    MESSAGE_MASS_SEND_URL(WX_API_BASE_URL, "/cgi-bin/message/mass/send"),
+    MESSAGE_MASS_SEND_URL(API_DEFAULT_HOST_URL, "/cgi-bin/message/mass/send"),
     /**
      * 群发消息预览接口.
      */
-    MESSAGE_MASS_PREVIEW_URL(WX_API_BASE_URL, "/cgi-bin/message/mass/preview"),
+    MESSAGE_MASS_PREVIEW_URL(API_DEFAULT_HOST_URL, "/cgi-bin/message/mass/preview"),
     /**
      * 删除群发接口.
      */
-    MESSAGE_MASS_DELETE_URL(WX_API_BASE_URL, "/cgi-bin/message/mass/delete");
+    MESSAGE_MASS_DELETE_URL(API_DEFAULT_HOST_URL, "/cgi-bin/message/mass/delete");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -674,50 +674,50 @@ enum Material implements WxMpApiUrl {
     /**
      * get.
      */
-    MEDIA_GET_URL(WX_API_BASE_URL, "/cgi-bin/media/get"),
+    MEDIA_GET_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/get"),
     /**
      * upload.
      */
-    MEDIA_UPLOAD_URL(WX_API_BASE_URL, "/cgi-bin/media/upload?type=%s"),
+    MEDIA_UPLOAD_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/upload?type=%s"),
     /**
      * uploadimg.
      */
-    IMG_UPLOAD_URL(WX_API_BASE_URL, "/cgi-bin/media/uploadimg"),
+    IMG_UPLOAD_URL(API_DEFAULT_HOST_URL, "/cgi-bin/media/uploadimg"),
     /**
      * add_material.
      */
-    MATERIAL_ADD_URL(WX_API_BASE_URL, "/cgi-bin/material/add_material?type=%s"),
+    MATERIAL_ADD_URL(API_DEFAULT_HOST_URL, "/cgi-bin/material/add_material?type=%s"),
     /**
      * add_news.
      */
-    NEWS_ADD_URL(WX_API_BASE_URL, "/cgi-bin/material/add_news"),
+    NEWS_ADD_URL(API_DEFAULT_HOST_URL, "/cgi-bin/material/add_news"),
     /**
      * get_material.
      */
-    MATERIAL_GET_URL(WX_API_BASE_URL, "/cgi-bin/material/get_material"),
+    MATERIAL_GET_URL(API_DEFAULT_HOST_URL, "/cgi-bin/material/get_material"),
     /**
      * update_news.
      */
-    NEWS_UPDATE_URL(WX_API_BASE_URL, "/cgi-bin/material/update_news"),
+    NEWS_UPDATE_URL(API_DEFAULT_HOST_URL, "/cgi-bin/material/update_news"),
     /**
      * del_material.
      */
-    MATERIAL_DEL_URL(WX_API_BASE_URL, "/cgi-bin/material/del_material"),
+    MATERIAL_DEL_URL(API_DEFAULT_HOST_URL, "/cgi-bin/material/del_material"),
     /**
      * get_materialcount.
      */
-    MATERIAL_GET_COUNT_URL(WX_API_BASE_URL, "/cgi-bin/material/get_materialcount"),
+    MATERIAL_GET_COUNT_URL(API_DEFAULT_HOST_URL, "/cgi-bin/material/get_materialcount"),
     /**
      * batchget_material.
      */
-    MATERIAL_BATCHGET_URL(WX_API_BASE_URL, "/cgi-bin/material/batchget_material");
+    MATERIAL_BATCHGET_URL(API_DEFAULT_HOST_URL, "/cgi-bin/material/batchget_material");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -726,43 +726,43 @@ enum MemberCard implements WxMpApiUrl {
     /**
      * create.
      */
-    MEMBER_CARD_CREATE(WX_API_BASE_URL, "/card/create"),
+    MEMBER_CARD_CREATE(API_DEFAULT_HOST_URL, "/card/create"),
     /**
      * activate.
      */
-    MEMBER_CARD_ACTIVATE(WX_API_BASE_URL, "/card/membercard/activate"),
+    MEMBER_CARD_ACTIVATE(API_DEFAULT_HOST_URL, "/card/membercard/activate"),
     /**
      * get userinfo.
      */
-    MEMBER_CARD_USER_INFO_GET(WX_API_BASE_URL, "/card/membercard/userinfo/get"),
+    MEMBER_CARD_USER_INFO_GET(API_DEFAULT_HOST_URL, "/card/membercard/userinfo/get"),
     /**
      * updateuser.
      */
-    MEMBER_CARD_UPDATE_USER(WX_API_BASE_URL, "/card/membercard/updateuser"),
+    MEMBER_CARD_UPDATE_USER(API_DEFAULT_HOST_URL, "/card/membercard/updateuser"),
     /**
      * 会员卡激活之微信开卡接口(wx_activate=true情况调用).
      */
-    MEMBER_CARD_ACTIVATE_USER_FORM(WX_API_BASE_URL, "/card/membercard/activateuserform/set"),
+    MEMBER_CARD_ACTIVATE_USER_FORM(API_DEFAULT_HOST_URL, "/card/membercard/activateuserform/set"),
     /**
      * 获取会员卡开卡插件参数.
      */
-    MEMBER_CARD_ACTIVATE_URL(WX_API_BASE_URL, "/card/membercard/activate/geturl"),
+    MEMBER_CARD_ACTIVATE_URL(API_DEFAULT_HOST_URL, "/card/membercard/activate/geturl"),
     /**
      * 会员卡信息更新.
      */
-    MEMBER_CARD_UPDATE(WX_API_BASE_URL, "/card/update"),
+    MEMBER_CARD_UPDATE(API_DEFAULT_HOST_URL, "/card/update"),
     /**
      * 跳转型会员卡开卡字段.
      * 获取用户提交资料(wx_activate=true情况调用),开发者根据activate_ticket获取到用户填写的信息
      */
-    MEMBER_CARD_ACTIVATE_TEMP_INFO(WX_API_BASE_URL, "/card/membercard/activatetempinfo/get");
+    MEMBER_CARD_ACTIVATE_TEMP_INFO(API_DEFAULT_HOST_URL, "/card/membercard/activatetempinfo/get");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -771,34 +771,34 @@ enum Store implements WxMpApiUrl {
     /**
      * getwxcategory.
      */
-    POI_GET_WX_CATEGORY_URL(WX_API_BASE_URL, "/cgi-bin/poi/getwxcategory"),
+    POI_GET_WX_CATEGORY_URL(API_DEFAULT_HOST_URL, "/cgi-bin/poi/getwxcategory"),
     /**
      * updatepoi.
      */
-    POI_UPDATE_URL(WX_API_BASE_URL, "/cgi-bin/poi/updatepoi"),
+    POI_UPDATE_URL(API_DEFAULT_HOST_URL, "/cgi-bin/poi/updatepoi"),
     /**
      * getpoilist.
      */
-    POI_LIST_URL(WX_API_BASE_URL, "/cgi-bin/poi/getpoilist"),
+    POI_LIST_URL(API_DEFAULT_HOST_URL, "/cgi-bin/poi/getpoilist"),
     /**
      * delpoi.
      */
-    POI_DEL_URL(WX_API_BASE_URL, "/cgi-bin/poi/delpoi"),
+    POI_DEL_URL(API_DEFAULT_HOST_URL, "/cgi-bin/poi/delpoi"),
     /**
      * getpoi.
      */
-    POI_GET_URL(WX_API_BASE_URL, "/cgi-bin/poi/getpoi"),
+    POI_GET_URL(API_DEFAULT_HOST_URL, "/cgi-bin/poi/getpoi"),
     /**
      * addpoi.
      */
-    POI_ADD_URL(WX_API_BASE_URL, "/cgi-bin/poi/addpoi");
+    POI_ADD_URL(API_DEFAULT_HOST_URL, "/cgi-bin/poi/addpoi");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 
@@ -808,30 +808,30 @@ enum User implements WxMpApiUrl {
     /**
      * batchget.
      */
-    USER_INFO_BATCH_GET_URL(WX_API_BASE_URL, "/cgi-bin/user/info/batchget"),
+    USER_INFO_BATCH_GET_URL(API_DEFAULT_HOST_URL, "/cgi-bin/user/info/batchget"),
     /**
      * get.
      */
-    USER_GET_URL(WX_API_BASE_URL, "/cgi-bin/user/get"),
+    USER_GET_URL(API_DEFAULT_HOST_URL, "/cgi-bin/user/get"),
     /**
      * info.
      */
-    USER_INFO_URL(WX_API_BASE_URL, "/cgi-bin/user/info"),
+    USER_INFO_URL(API_DEFAULT_HOST_URL, "/cgi-bin/user/info"),
     /**
      * updateremark.
      */
-    USER_INFO_UPDATE_REMARK_URL(WX_API_BASE_URL, "/cgi-bin/user/info/updateremark"),
+    USER_INFO_UPDATE_REMARK_URL(API_DEFAULT_HOST_URL, "/cgi-bin/user/info/updateremark"),
     /**
      * changeopenid.
      */
-    USER_CHANGE_OPENID_URL(WX_API_BASE_URL, "/cgi-bin/changeopenid");
+    USER_CHANGE_OPENID_URL(API_DEFAULT_HOST_URL, "/cgi-bin/changeopenid");
 
     private String prefix;
     private String path;
 
     @Override
-    public String getUrl() {
-      return this.prefix + this.path;
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java
index b16775b40b..1d1ae9095f 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java
@@ -17,6 +17,9 @@
 import me.chanjar.weixin.mp.bean.template.WxMpTemplateIndustry;
 import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
 
+/**
+ * @author someone
+ */
 public class WxMpGsonBuilder {
 
   private static final GsonBuilder INSTANCE = new GsonBuilder();
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 da34e808d4..ef699212bf 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
@@ -11,6 +11,7 @@
 import me.chanjar.weixin.common.bean.WxAccessToken;
 import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
 import me.chanjar.weixin.mp.api.WxMpConfigStorage;
+import me.chanjar.weixin.mp.bean.WxMpHostConfig;
 import me.chanjar.weixin.mp.enums.TicketType;
 import me.chanjar.weixin.open.api.WxOpenConfigStorage;
 import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken;
@@ -543,10 +544,14 @@ public ApacheHttpClientBuilder getApacheHttpClientBuilder() {
       return wxOpenConfigStorage.getApacheHttpClientBuilder();
     }
 
-
     @Override
     public boolean autoRefreshToken() {
       return true;
     }
+
+    @Override
+    public WxMpHostConfig getHostConfig() {
+      return null;
+    }
   }
 }
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java
index a946fb7014..104215bb9e 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java
@@ -9,7 +9,7 @@
 /**
  * @author 007
  */
-/* package */ class WxOpenMpServiceImpl extends WxMpServiceImpl {
+/* package(无需对外暴露) */ class WxOpenMpServiceImpl extends WxMpServiceImpl {
   private WxOpenComponentService wxOpenComponentService;
   private WxMpConfigStorage wxMpConfigStorage;
   private String appId;

From cb4e3f3eb057e85e4e61cdad6e0e83fe80a9b036 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sun, 9 Jun 2019 21:50:20 +0800
Subject: [PATCH 21/74] =?UTF-8?q?=E5=8F=91=E5=B8=833.4.3.B=E6=B5=8B?=
 =?UTF-8?q?=E8=AF=95=E7=89=88=E6=9C=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pom.xml                              | 2 +-
 starters/wx-java-mp-starter/pom.xml  | 2 +-
 starters/wx-java-pay-starter/pom.xml | 2 +-
 weixin-java-common/pom.xml           | 2 +-
 weixin-java-cp/pom.xml               | 2 +-
 weixin-java-miniapp/pom.xml          | 2 +-
 weixin-java-mp/pom.xml               | 2 +-
 weixin-java-open/pom.xml             | 2 +-
 weixin-java-pay/pom.xml              | 2 +-
 9 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/pom.xml b/pom.xml
index 8f74380695..a25d8a7aa8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
   4.0.0
   com.github.binarywang
   wx-java
-  3.4.2.B
+  3.4.3.B
   pom
   WxJava - Weixin/Wechat Java SDK
   微信开发Java SDK
diff --git a/starters/wx-java-mp-starter/pom.xml b/starters/wx-java-mp-starter/pom.xml
index 1edd7350ea..ddf6ad6dbf 100644
--- a/starters/wx-java-mp-starter/pom.xml
+++ b/starters/wx-java-mp-starter/pom.xml
@@ -6,7 +6,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.2.B
+    3.4.3.B
     ../../
   
 
diff --git a/starters/wx-java-pay-starter/pom.xml b/starters/wx-java-pay-starter/pom.xml
index 0f9fce58ac..96b607686b 100644
--- a/starters/wx-java-pay-starter/pom.xml
+++ b/starters/wx-java-pay-starter/pom.xml
@@ -5,7 +5,7 @@
   
     wx-java
     com.github.binarywang
-    3.4.2.B
+    3.4.3.B
     ../../
   
   4.0.0
diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml
index 539d61ef28..b847c8e5ed 100644
--- a/weixin-java-common/pom.xml
+++ b/weixin-java-common/pom.xml
@@ -6,7 +6,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.2.B
+    3.4.3.B
   
 
   weixin-java-common
diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml
index 22624b9b92..1f557ea030 100644
--- a/weixin-java-cp/pom.xml
+++ b/weixin-java-cp/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.2.B
+    3.4.3.B
   
 
   weixin-java-cp
diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml
index 3f7f662acb..fbe2dfc74f 100644
--- a/weixin-java-miniapp/pom.xml
+++ b/weixin-java-miniapp/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.2.B
+    3.4.3.B
   
 
   weixin-java-miniapp
diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml
index 698859868f..454abd3ea6 100644
--- a/weixin-java-mp/pom.xml
+++ b/weixin-java-mp/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.2.B
+    3.4.3.B
   
 
   weixin-java-mp
diff --git a/weixin-java-open/pom.xml b/weixin-java-open/pom.xml
index 10364fba7c..7dbb76e51d 100644
--- a/weixin-java-open/pom.xml
+++ b/weixin-java-open/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.2.B
+    3.4.3.B
   
 
   weixin-java-open
diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml
index 4fd46c21d9..ae87556be8 100644
--- a/weixin-java-pay/pom.xml
+++ b/weixin-java-pay/pom.xml
@@ -5,7 +5,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.2.B
+    3.4.3.B
   
   4.0.0
 

From a4f5aa341b04740ba83e30dcfc98dad13c272900 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sun, 16 Jun 2019 21:35:18 +0800
Subject: [PATCH 22/74] =?UTF-8?q?#1075=20=E4=BC=81=E4=B8=9A=E5=BE=AE?=
 =?UTF-8?q?=E4=BF=A1=E6=94=AF=E6=8C=81=E6=8E=A8=E9=80=81=E5=B0=8F=E7=A8=8B?=
 =?UTF-8?q?=E5=BA=8F=E9=80=9A=E7=9F=A5=E6=B6=88=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../chanjar/weixin/common/api/WxConsts.java   |  5 ++
 .../chanjar/weixin/cp/bean/WxCpMessage.java   | 58 ++++++++++++----
 .../MiniProgramNoticeMsgBuilder.java          | 69 +++++++++++++++++++
 .../weixin/cp/api/WxCpMessageAPITest.java     | 24 +++++++
 4 files changed, 144 insertions(+), 12 deletions(-)
 create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/MiniProgramNoticeMsgBuilder.java

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 75cb54dcf3..37820bbde5 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
@@ -98,6 +98,11 @@ public static class KefuMsgType {
      * 菜单消息.
      */
     public static final String MSGMENU = "msgmenu";
+
+    /**
+     * 小程序通知消息.
+     */
+    public static final String MINIPROGRAM_NOTICE = "miniprogram_notice";
   }
 
   /**
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java
index a22efd0e45..b07e3d5451 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java
@@ -8,11 +8,15 @@
 import me.chanjar.weixin.cp.bean.article.NewArticle;
 import me.chanjar.weixin.cp.bean.messagebuilder.*;
 import me.chanjar.weixin.cp.bean.taskcard.TaskCardButton;
+import me.chanjar.weixin.cp.constant.WxCpConsts;
 import org.apache.commons.lang3.StringUtils;
 
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+
+import static me.chanjar.weixin.common.api.WxConsts.KefuMsgType.*;
 
 /**
  * 消息.
@@ -40,9 +44,13 @@ public class WxCpMessage implements Serializable {
   private String btnTxt;
   private List articles = new ArrayList<>();
   private List mpnewsArticles = new ArrayList<>();
+  private String appId;
+  private String page;
+  private Boolean emphasisFirstItem;
+  private Map contentItems;
 
   /**
-   * 任务卡片特有的属性
+   * 任务卡片特有的属性.
    */
   private String taskId;
   private List taskButtons = new ArrayList<>();
@@ -117,10 +125,16 @@ public static TaskCardBuilder TASKCARD() {
     return new TaskCardBuilder();
   }
 
+  /**
+   * 获得小程序通知消息builder.
+   */
+  public static MiniProgramNoticeMsgBuilder newMiniProgramNoticeBuilder() {
+    return new MiniProgramNoticeMsgBuilder();
+  }
 
   /**
    * 
-   * 请使用
+   * 请使用.
    * {@link KefuMsgType#TEXT}
    * {@link KefuMsgType#IMAGE}
    * {@link KefuMsgType#VOICE}
@@ -130,6 +144,7 @@ public static TaskCardBuilder TASKCARD() {
    * {@link KefuMsgType#MPNEWS}
    * {@link KefuMsgType#MARKDOWN}
    * {@link KefuMsgType#TASKCARD}
+   * {@link KefuMsgType#MINIPROGRAM_NOTICE}
    * 
* * @param msgType 消息类型 @@ -169,19 +184,19 @@ public String toJson() { private void handleMsgType(JsonObject messageJson) { switch (this.getMsgType()) { - case KefuMsgType.TEXT: { + case TEXT: { JsonObject text = new JsonObject(); text.addProperty("content", this.getContent()); messageJson.add("text", text); break; } - case KefuMsgType.MARKDOWN: { + case MARKDOWN: { JsonObject text = new JsonObject(); text.addProperty("content", this.getContent()); messageJson.add("markdown", text); break; } - case KefuMsgType.TEXTCARD: { + case TEXTCARD: { JsonObject text = new JsonObject(); text.addProperty("title", this.getTitle()); text.addProperty("description", this.getDescription()); @@ -190,25 +205,25 @@ private void handleMsgType(JsonObject messageJson) { messageJson.add("textcard", text); break; } - case KefuMsgType.IMAGE: { + case IMAGE: { JsonObject image = new JsonObject(); image.addProperty("media_id", this.getMediaId()); messageJson.add("image", image); break; } - case KefuMsgType.FILE: { + case FILE: { JsonObject image = new JsonObject(); image.addProperty("media_id", this.getMediaId()); messageJson.add("file", image); break; } - case KefuMsgType.VOICE: { + case VOICE: { JsonObject voice = new JsonObject(); voice.addProperty("media_id", this.getMediaId()); messageJson.add("voice", voice); break; } - case KefuMsgType.VIDEO: { + case VIDEO: { JsonObject video = new JsonObject(); video.addProperty("media_id", this.getMediaId()); video.addProperty("thumb_media_id", this.getThumbMediaId()); @@ -217,7 +232,7 @@ private void handleMsgType(JsonObject messageJson) { messageJson.add("video", video); break; } - case KefuMsgType.NEWS: { + case NEWS: { JsonObject newsJsonObject = new JsonObject(); JsonArray articleJsonArray = new JsonArray(); for (NewArticle article : this.getArticles()) { @@ -232,7 +247,7 @@ private void handleMsgType(JsonObject messageJson) { messageJson.add("news", newsJsonObject); break; } - case KefuMsgType.MPNEWS: { + case MPNEWS: { JsonObject newsJsonObject = new JsonObject(); if (this.getMediaId() != null) { newsJsonObject.addProperty("media_id", this.getMediaId()); @@ -255,7 +270,7 @@ private void handleMsgType(JsonObject messageJson) { messageJson.add("mpnews", newsJsonObject); break; } - case KefuMsgType.TASKCARD: { + case TASKCARD: { JsonObject text = new JsonObject(); text.addProperty("title", this.getTitle()); text.addProperty("description", this.getDescription()); @@ -291,6 +306,25 @@ private void handleMsgType(JsonObject messageJson) { messageJson.add("taskcard", text); break; } + case MINIPROGRAM_NOTICE: { + JsonObject notice = new JsonObject(); + notice.addProperty("appid", this.getAppId()); + notice.addProperty("page", this.getPage()); + notice.addProperty("description", this.getDescription()); + notice.addProperty("title", this.getTitle()); + notice.addProperty("emphasis_first_item", this.getEmphasisFirstItem()); + JsonArray content = new JsonArray(); + for (Map.Entry item : this.getContentItems().entrySet()) { + JsonObject articleJson = new JsonObject(); + articleJson.addProperty("key", item.getKey()); + articleJson.addProperty("value", item.getValue()); + content.add(articleJson); + } + notice.add("content_item", content); + + messageJson.add("miniprogram_notice", notice); + break; + } default: { // do nothing } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/MiniProgramNoticeMsgBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/MiniProgramNoticeMsgBuilder.java new file mode 100644 index 0000000000..cf44c0f0f7 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/MiniProgramNoticeMsgBuilder.java @@ -0,0 +1,69 @@ +package me.chanjar.weixin.cp.bean.messagebuilder; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.cp.bean.WxCpMessage; + +import java.util.Map; + +/** + *
+ * miniprogram_notice 类型的消息 builder
+ * Created by Binary Wang on 2019/6/16.
+ * 
+ * + * @author Binary Wang + */ +public class MiniProgramNoticeMsgBuilder extends BaseBuilder { + private String title; + private String description; + private String appId; + private String page; + private Boolean emphasisFirstItem; + private Map contentItems; + + public MiniProgramNoticeMsgBuilder() { + this.msgType = WxConsts.KefuMsgType.MINIPROGRAM_NOTICE; + } + + public MiniProgramNoticeMsgBuilder appId(String appId) { + this.appId = appId; + return this; + } + + public MiniProgramNoticeMsgBuilder page(String page) { + this.page = page; + return this; + } + + public MiniProgramNoticeMsgBuilder title(String title) { + this.title = title; + return this; + } + + public MiniProgramNoticeMsgBuilder description(String description) { + this.description = description; + return this; + } + + public MiniProgramNoticeMsgBuilder contentItems(Map contentItems) { + this.contentItems = contentItems; + return this; + } + + public MiniProgramNoticeMsgBuilder emphasisFirstItem(Boolean emphasisFirstItem) { + this.emphasisFirstItem = emphasisFirstItem; + return this; + } + + @Override + public WxCpMessage build() { + WxCpMessage m = super.build(); + m.setContentItems(this.contentItems); + m.setAppId(this.appId); + m.setDescription(this.description); + m.setTitle(this.title); + m.setEmphasisFirstItem(this.emphasisFirstItem); + m.setPage(this.page); + return m; + } +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java index 5c93f38fb1..d0984565aa 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageAPITest.java @@ -1,5 +1,6 @@ package me.chanjar.weixin.cp.api; +import com.google.common.collect.ImmutableMap; import org.testng.annotations.*; import com.google.inject.Inject; @@ -107,4 +108,27 @@ public void testSendMessage_textCard() throws WxErrorException { System.out.println(messageSendResult.getInvalidUserList()); System.out.println(messageSendResult.getInvalidTagList()); } + + @Test + public void testSendMessage_miniprogram_notice() throws WxErrorException { + WxCpMessage message = WxCpMessage + .newMiniProgramNoticeBuilder() + .toUser(configStorage.getUserId()) + .appId("wx123123123123123") + .page("pages/index?userid=zhangsan&orderid=123123123") + .title("会议室预订成功通知") + .description("4月27日 16:16") + .emphasisFirstItem(true) + .contentItems(ImmutableMap.of("会议室","402", + "会议地点","广州TIT-402会议室", + "会议时间","2018年8月1日 09:00-09:30")) + .build(); + + WxCpMessageSendResult messageSendResult = this.wxService.messageSend(message); + assertNotNull(messageSendResult); + System.out.println(messageSendResult); + System.out.println(messageSendResult.getInvalidPartyList()); + System.out.println(messageSendResult.getInvalidUserList()); + System.out.println(messageSendResult.getInvalidTagList()); + } } From 9c149bb1e2ee84738ea66b9a82c295b3fa7ccf95 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 16 Jun 2019 23:07:11 +0800 Subject: [PATCH 23/74] =?UTF-8?q?#516=20=E6=B7=BB=E5=8A=A0WiFi=E9=97=A8?= =?UTF-8?q?=E5=BA=97=E7=AE=A1=E7=90=86=E6=9F=A5=E8=AF=A2=E9=97=A8=E5=BA=97?= =?UTF-8?q?Wi-Fi=E4=BF=A1=E6=81=AF=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/mp/api/WxMpWifiService.java | 22 +++- .../mp/api/impl/WxMpWifiServiceImpl.java | 12 +- .../mp/bean/wifi/WxMpWifiShopDataResult.java | 114 ++++++++++++++++++ .../mp/bean/wifi/WxMpWifiShopListResult.java | 23 ++-- .../chanjar/weixin/mp/enums/WxMpApiUrl.java | 7 +- .../mp/api/impl/WxMpWifiServiceImplTest.java | 61 +++++++++- 6 files changed, 224 insertions(+), 15 deletions(-) create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/wifi/WxMpWifiShopDataResult.java diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpWifiService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpWifiService.java index 9cda53bbb5..1ba40a7714 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpWifiService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpWifiService.java @@ -1,6 +1,7 @@ package me.chanjar.weixin.mp.api; import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.bean.wifi.WxMpWifiShopDataResult; import me.chanjar.weixin.mp.bean.wifi.WxMpWifiShopListResult; /** @@ -21,8 +22,27 @@ public interface WxMpWifiService { * http请求方式: POST * 请求URL:https://api.weixin.qq.com/bizwifi/shop/list?access_token=ACCESS_TOKEN *
- * @param pageIndex 分页下标,默认从1开始 + * + * @param pageIndex 分页下标,默认从1开始 * @param pageSize 每页的个数,默认10个,最大20个 + * @return 结果 + * @throws WxErrorException 异常 */ WxMpWifiShopListResult listShop(int pageIndex, int pageSize) throws WxErrorException; + + /** + *
+   * 查询门店Wi-Fi信息
+   * 通过此接口查询某一门店的详细Wi-Fi信息,包括门店内的设备类型、ssid、密码、设备数量、商家主页URL、顶部常驻入口文案。
+   *
+   * http请求方式: POST
+   * 请求URL:https://api.weixin.qq.com/bizwifi/shop/get?access_token=ACCESS_TOKEN
+   * POST数据格式:JSON
+   * 
+ * + * @param shopId 门店ID + * @return 结果 + * @throws WxErrorException 异常 + */ + WxMpWifiShopDataResult getShopWifiInfo(int shopId) throws WxErrorException; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java index 357ae58014..636ba4fe30 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java @@ -5,10 +5,11 @@ import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpWifiService; +import me.chanjar.weixin.mp.bean.wifi.WxMpWifiShopDataResult; import me.chanjar.weixin.mp.bean.wifi.WxMpWifiShopListResult; -import me.chanjar.weixin.mp.enums.WxMpApiUrl; -import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Wifi.*; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Wifi.BIZWIFI_SHOP_GET; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Wifi.BIZWIFI_SHOP_LIST; /** *
@@ -29,4 +30,11 @@ public WxMpWifiShopListResult listShop(int pageIndex, int pageSize) throws WxErr
     final String result = this.wxMpService.post(BIZWIFI_SHOP_LIST, json.toString());
     return WxMpWifiShopListResult.fromJson(result);
   }
+
+  @Override
+  public WxMpWifiShopDataResult getShopWifiInfo(int shopId) throws WxErrorException {
+    JsonObject json = new JsonObject();
+    json.addProperty("shop_id", shopId);
+    return WxMpWifiShopDataResult.fromJson(this.wxMpService.post(BIZWIFI_SHOP_GET, json.toString()));
+  }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/wifi/WxMpWifiShopDataResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/wifi/WxMpWifiShopDataResult.java
new file mode 100644
index 0000000000..2a3c795022
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/wifi/WxMpWifiShopDataResult.java
@@ -0,0 +1,114 @@
+package me.chanjar.weixin.mp.bean.wifi;
+
+import com.google.gson.JsonParser;
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
+
+import java.util.List;
+
+/**
+ * 门店Wi-Fi信息.
+ *
+ * @author Binary Wang
+ * @date 2019-06-16
+ */
+@Data
+public class WxMpWifiShopDataResult {
+  public static WxMpWifiShopDataResult fromJson(String json) {
+    return WxMpGsonBuilder.create().fromJson(
+      new JsonParser().parse(json).getAsJsonObject().get("data"),
+      WxMpWifiShopDataResult.class);
+  }
+
+  /**
+   * 门店名称.
+   */
+  @SerializedName("shop_name")
+  private String shopName;
+
+  /**
+   * 无线网络设备的ssid,未添加设备为空,多个ssid时显示第一个.
+   */
+  @SerializedName("ssid")
+  private String ssid;
+
+  /**
+   * 无线网络设备的ssid列表,返回数组格式.
+   */
+  @SerializedName("ssid_list")
+  private String[] ssidList;
+
+  /**
+   * ssid和密码的列表,数组格式。当为密码型设备时,密码才有值.
+   */
+  @SerializedName("ssid_password_list")
+  private List ssidPasswordList;
+
+  /**
+   * 设备密码,当设备类型为密码型时返回.
+   */
+  @SerializedName("password")
+  private String password;
+
+  /**
+   * 门店内设备的设备类型,0-未添加设备,4-密码型设备,31-portal型设备.
+   */
+  @SerializedName("protocol_type")
+  private Integer protocolType;
+
+  /**
+   * 门店内设备总数.
+   */
+  @SerializedName("ap_count")
+  private Integer apCount;
+
+  /**
+   * 商家主页模板类型.
+   */
+  @SerializedName("template_id")
+  private Integer templateId;
+
+  /**
+   * 商家主页链接.
+   */
+  @SerializedName("homepage_url")
+  private String homepageUrl;
+
+  /**
+   * 顶部常驻入口上显示的文本内容:0--欢迎光临+公众号名称;1--欢迎光临+门店名称;2--已连接+公众号名称+WiFi;3--已连接+门店名称+Wi-Fi.
+   */
+  @SerializedName("bar_type")
+  private Integer barType;
+
+  /**
+   * 连网完成页链接.
+   */
+  @SerializedName("finishpage_url")
+  private String finishPageUrl;
+  
+  /**
+   * 商户自己的id,与门店poi_id对应关系,建议在添加门店时候建立关联关系,具体请参考“微信门店接口”.
+   */
+  @SerializedName("sid")
+  private String sid;
+
+  /**
+   * 门店ID(适用于微信卡券、微信门店业务),具体定义参考微信门店,与shop_id一一对应.
+   */
+  @SerializedName("poi_id")
+  private String poiId;
+
+  @Data
+  public static class SsidPassword {
+    /**
+     * 无线网络设备的ssid.
+     */
+    private String ssid;
+
+    /**
+     * 无线网络设备的password.
+     */
+    private String password;
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/wifi/WxMpWifiShopListResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/wifi/WxMpWifiShopListResult.java
index 69947aefcd..4a86acb353 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/wifi/WxMpWifiShopListResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/wifi/WxMpWifiShopListResult.java
@@ -23,19 +23,19 @@ public static WxMpWifiShopListResult fromJson(String json) {
   }
 
   /**
-   * 总数
+   * 总数.
    */
   @SerializedName("totalcount")
   private int totalCount;
 
   /**
-   * 分页下标
+   * 分页下标.
    */
   @SerializedName("pageindex")
   private int pageIndex;
 
   /**
-   * 分页页数
+   * 分页页数.
    */
   @SerializedName("pagecount")
   private int pageCount;
@@ -46,43 +46,46 @@ public static WxMpWifiShopListResult fromJson(String json) {
   public static class Record {
 
     /**
-     * 门店ID(适用于微信连Wi-Fi业务)
+     * 门店ID(适用于微信连Wi-Fi业务).
      */
     @SerializedName("shop_id")
     private Integer shopId;
 
     /**
-     * 门店名称
+     * 门店名称.
      */
     @SerializedName("shop_name")
     private String shopName;
 
     /**
-     * 无线网络设备的ssid,未添加设备为空,多个ssid时显示第一个
+     * 无线网络设备的ssid,未添加设备为空,多个ssid时显示第一个.
      */
     @SerializedName("ssid")
     private String ssid;
 
     /**
-     * 无线网络设备的ssid列表,返回数组格式
+     * 无线网络设备的ssid列表,返回数组格式.
      */
     @SerializedName("ssid_list")
     private List ssidList;
 
     /**
-     * 门店内设备的设备类型,0-未添加设备,1-专业型设备,4-密码型设备,5-portal自助型设备,31-portal改造型设备
+     * 门店内设备的设备类型.
+     * 0-未添加设备,1-专业型设备,4-密码型设备,5-portal自助型设备,31-portal改造型设备
      */
     @SerializedName("protocol_type")
     private Integer protocolType;
 
     /**
-     * 商户自己的id,与门店poi_id对应关系,建议在添加门店时候建立关联关系,具体请参考“微信门店接口”
+     * 商户自己的id.
+     * 与门店poi_id对应关系,建议在添加门店时候建立关联关系,具体请参考“微信门店接口”
      */
     @SerializedName("sid")
     private String sid;
 
     /**
-     * 门店ID(适用于微信卡券、微信门店业务),具体定义参考微信门店,与shop_id一一对应
+     * 门店ID(适用于微信卡券、微信门店业务).
+     * 具体定义参考微信门店,与shop_id一一对应
      */
     @SerializedName("poi_id")
     private String poiId;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java
index e25e251e1c..fd32840c71 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java
@@ -386,7 +386,12 @@ enum Wifi implements WxMpApiUrl {
     /**
      * list.
      */
-    BIZWIFI_SHOP_LIST(API_DEFAULT_HOST_URL, "/bizwifi/shop/list");
+    BIZWIFI_SHOP_LIST(API_DEFAULT_HOST_URL, "/bizwifi/shop/list"),
+
+    /**
+     * get.
+     */
+    BIZWIFI_SHOP_GET(API_DEFAULT_HOST_URL, "/bizwifi/shop/get");
 
     private String prefix;
     private String path;
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImplTest.java
index e129474e39..9ef98f77fe 100644
--- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImplTest.java
+++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImplTest.java
@@ -4,11 +4,17 @@
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.api.test.ApiTestModule;
+import me.chanjar.weixin.mp.bean.wifi.WxMpWifiShopDataResult;
 import me.chanjar.weixin.mp.bean.wifi.WxMpWifiShopListResult;
 import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
-import static org.testng.Assert.*;
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Wifi.BIZWIFI_SHOP_GET;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 /**
  * 
@@ -26,6 +32,59 @@ public class WxMpWifiServiceImplTest {
   @Test
   public void testListShop() throws WxErrorException {
     final WxMpWifiShopListResult result = this.wxService.getWifiService().listShop(1, 2);
+    assertThat(result).isNotNull();
     System.out.println(result);
   }
+
+  @Test
+  public void testGetShopWifiInfo() throws WxErrorException {
+    final WxMpWifiShopDataResult wifiInfo = this.wxService.getWifiService().getShopWifiInfo(123);
+    assertThat(wifiInfo).isNotNull();
+    System.out.println(wifiInfo);
+  }
+
+  public static class MockTest {
+    private WxMpService wxService = mock(WxMpService.class);
+
+    @Test
+    public void testGetShopWifiInfo() throws Exception {
+      String returnJson = "{\n" +
+        "  \"errcode\": 0,\n" +
+        "  \"data\": {\n" +
+        "    \"shop_name\": \"南山店\",\n" +
+        "    \"ssid\": \" WX123\",\n" +
+        "    \"ssid_list\": [\n" +
+        "      \"WX123\",\n" +
+        "      \"WX456\"\n" +
+        "    ],\n" +
+        "    \"ssid_password_list\": [\n" +
+        "      {\n" +
+        "        \"ssid\": \"WX123\",\n" +
+        "        \"password\": \"123456789\"\n" +
+        "      },\n" +
+        "      {\n" +
+        "        \"ssid\": \"WX456\",\n" +
+        "        \"password\": \"21332465dge\"\n" +
+        "      }\n" +
+        "    ],\n" +
+        "    \"password\": \"123456789\",\n" +
+        "    \"protocol_type\": 4,\n" +
+        "    \"ap_count\": 2,\n" +
+        "    \"template_id\": 1,\n" +
+        "    \"homepage_url\": \"http://www.weixin.qq.com/\",\n" +
+        "    \"bar_type\": 1,\n" +
+        "    \"sid\":\"\",\n" +
+        "    \"poi_id\":\"285633617\"\n" +
+        "  }\n" +
+        "}";
+
+      when(wxService.post(eq(BIZWIFI_SHOP_GET), anyString())).thenReturn(returnJson);
+      when(wxService.getWifiService()).thenReturn(new WxMpWifiServiceImpl(wxService));
+
+      final WxMpWifiShopDataResult wifiInfo = this.wxService.getWifiService().getShopWifiInfo(123);
+      assertThat(wifiInfo).isNotNull();
+      System.out.println(wifiInfo);
+
+    }
+  }
 }

From be78d8c1251400b8068c639a5a197b8a2bdddaba Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sun, 16 Jun 2019 23:41:08 +0800
Subject: [PATCH 24/74] =?UTF-8?q?#252=20=E6=B7=BB=E5=8A=A0=E5=9B=BE?=
 =?UTF-8?q?=E6=96=87=E6=B6=88=E6=81=AF=E7=95=99=E8=A8=80=E7=AE=A1=E7=90=86?=
 =?UTF-8?q?=E4=B8=AD=E6=89=93=E5=BC=80=E5=B7=B2=E7=BE=A4=E5=8F=91=E6=96=87?=
 =?UTF-8?q?=E7=AB=A0=E8=AF=84=E8=AE=BA=E7=9A=84=E6=8E=A5=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../weixin/mp/api/WxMpCommentService.java     | 22 +++++++++++++++
 .../me/chanjar/weixin/mp/api/WxMpService.java |  9 ++++++
 .../mp/api/impl/BaseWxMpServiceImpl.java      | 11 ++++++++
 .../mp/api/impl/WxMpCommentServiceImpl.java   | 27 ++++++++++++++++++
 .../chanjar/weixin/mp/enums/WxMpApiUrl.java   | 17 ++++++++++-
 .../api/impl/WxMpCommentServiceImplTest.java  | 28 +++++++++++++++++++
 6 files changed, 113 insertions(+), 1 deletion(-)
 create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCommentService.java
 create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCommentServiceImpl.java
 create mode 100644 weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpCommentServiceImplTest.java

diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCommentService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCommentService.java
new file mode 100644
index 0000000000..2ba7a09235
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpCommentService.java
@@ -0,0 +1,22 @@
+package me.chanjar.weixin.mp.api;
+
+import me.chanjar.weixin.common.error.WxErrorException;
+
+/**
+ * 评论数据管理.
+ *
+ * @author Binary Wang
+ * @date 2019-06-16
+ */
+public interface WxMpCommentService {
+  /**
+   * 打开已群发文章评论.
+   * https://api.weixin.qq.com/cgi-bin/comment/open?access_token=ACCESS_TOKEN
+   * 参数	是否必须	类型	说明
+   *
+   * @param msgDataId 群发返回的msg_data_id
+   * @param index     多图文时,用来指定第几篇图文,从0开始,不带默认操作该msg_data_id的第一篇图文
+   * @throws WxErrorException 异常
+   */
+  void open(Integer msgDataId, Integer index) throws WxErrorException;
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
index 92d17dbb7e..35debff565 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
@@ -526,4 +526,13 @@ public interface WxMpService {
   void setAiOpenService(WxMpAiOpenService aiOpenService);
 
   void setMarketingService(WxMpMarketingService marketingService);
+
+  /**
+   * 返回评论数据管理接口方法的实现类对象,以方便调用其各个接口.
+   *
+   * @return WxMpWifiService
+   */
+  WxMpCommentService getCommentService();
+
+  void setCommentService(WxMpCommentService commentService);
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java
index fc467e99e9..98220cd9a0 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java
@@ -62,6 +62,7 @@ public abstract class BaseWxMpServiceImpl implements WxMpService, RequestH
   private WxMpAiOpenService aiOpenService = new WxMpAiOpenServiceImpl(this);
   private WxMpWifiService wifiService = new WxMpWifiServiceImpl(this);
   private WxMpMarketingService marketingService = new WxMpMarketingServiceImpl(this);
+  private WxMpCommentService commentService = new WxMpCommentServiceImpl(this);
 
   private Map configStorageMap;
 
@@ -608,4 +609,14 @@ public WxMpMarketingService getMarketingService() {
   public void setMarketingService(WxMpMarketingService marketingService) {
     this.marketingService = marketingService;
   }
+
+  @Override
+  public WxMpCommentService getCommentService() {
+    return this.commentService;
+  }
+
+  @Override
+  public void setCommentService(WxMpCommentService commentService) {
+    this.commentService = commentService;
+  }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCommentServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCommentServiceImpl.java
new file mode 100644
index 0000000000..f58280aeee
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCommentServiceImpl.java
@@ -0,0 +1,27 @@
+package me.chanjar.weixin.mp.api.impl;
+
+import com.google.gson.JsonObject;
+import lombok.RequiredArgsConstructor;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.mp.api.WxMpCommentService;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.enums.WxMpApiUrl;
+
+/**
+ * @author Binary Wang
+ * @date 2019-06-16
+ */
+@RequiredArgsConstructor
+public class WxMpCommentServiceImpl implements WxMpCommentService {
+  private final WxMpService wxMpService;
+
+  @Override
+  public void open(Integer msgDataId, Integer index) throws WxErrorException {
+    JsonObject json = new JsonObject();
+    json.addProperty("msg_data_id", msgDataId);
+    if (index != null) {
+      json.addProperty("index", index);
+    }
+    this.wxMpService.post(WxMpApiUrl.Comment.OPEN, json.toString());
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java
index fd32840c71..276c1c9e65 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java
@@ -807,7 +807,6 @@ public String getUrl(WxMpConfigStorage config) {
     }
   }
 
-
   @AllArgsConstructor
   enum User implements WxMpApiUrl {
     /**
@@ -839,4 +838,20 @@ public String getUrl(WxMpConfigStorage config) {
       return buildUrl(config.getHostConfig(), prefix, path);
     }
   }
+
+  @AllArgsConstructor
+  enum Comment implements WxMpApiUrl {
+    /**
+     * 打开已群发文章评论.
+     */
+    OPEN(API_DEFAULT_HOST_URL, "/cgi-bin/comment/open");
+
+    private String prefix;
+    private String path;
+
+    @Override
+    public String getUrl(WxMpConfigStorage config) {
+      return buildUrl(config.getHostConfig(), prefix, path);
+    }
+  }
 }
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpCommentServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpCommentServiceImplTest.java
new file mode 100644
index 0000000000..60551c323d
--- /dev/null
+++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpCommentServiceImplTest.java
@@ -0,0 +1,28 @@
+package me.chanjar.weixin.mp.api.impl;
+
+import com.google.inject.Inject;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.api.test.ApiTestModule;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+/**
+ * 测试类.
+ *
+ * @author Binary Wang
+ * @date 2019-06-16
+ */
+
+@Test
+@Guice(modules = ApiTestModule.class)
+public class WxMpCommentServiceImplTest {
+  @Inject
+  private WxMpService wxService;
+
+  @Test
+  public void testOpen() throws WxErrorException {
+    this.wxService.getCommentService().open(1, null);
+    this.wxService.getCommentService().open(1, 0);
+  }
+}

From fdf14977ba9c17d0e947df52bcf0f0cb8e33bd59 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Mon, 17 Jun 2019 00:04:39 +0800
Subject: [PATCH 25/74] =?UTF-8?q?=E5=8F=91=E5=B8=833.4.4.B=E6=B5=8B?=
 =?UTF-8?q?=E8=AF=95=E7=89=88=E6=9C=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pom.xml                              | 2 +-
 starters/wx-java-mp-starter/pom.xml  | 2 +-
 starters/wx-java-pay-starter/pom.xml | 2 +-
 weixin-java-common/pom.xml           | 2 +-
 weixin-java-cp/pom.xml               | 2 +-
 weixin-java-miniapp/pom.xml          | 2 +-
 weixin-java-mp/pom.xml               | 2 +-
 weixin-java-open/pom.xml             | 2 +-
 weixin-java-pay/pom.xml              | 2 +-
 9 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/pom.xml b/pom.xml
index a25d8a7aa8..f6847b14f4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
   4.0.0
   com.github.binarywang
   wx-java
-  3.4.3.B
+  3.4.4.B
   pom
   WxJava - Weixin/Wechat Java SDK
   微信开发Java SDK
diff --git a/starters/wx-java-mp-starter/pom.xml b/starters/wx-java-mp-starter/pom.xml
index ddf6ad6dbf..6836b174b7 100644
--- a/starters/wx-java-mp-starter/pom.xml
+++ b/starters/wx-java-mp-starter/pom.xml
@@ -6,7 +6,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.3.B
+    3.4.4.B
     ../../
   
 
diff --git a/starters/wx-java-pay-starter/pom.xml b/starters/wx-java-pay-starter/pom.xml
index 96b607686b..a74a48d277 100644
--- a/starters/wx-java-pay-starter/pom.xml
+++ b/starters/wx-java-pay-starter/pom.xml
@@ -5,7 +5,7 @@
   
     wx-java
     com.github.binarywang
-    3.4.3.B
+    3.4.4.B
     ../../
   
   4.0.0
diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml
index b847c8e5ed..6e589255e4 100644
--- a/weixin-java-common/pom.xml
+++ b/weixin-java-common/pom.xml
@@ -6,7 +6,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.3.B
+    3.4.4.B
   
 
   weixin-java-common
diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml
index 1f557ea030..d6305ef174 100644
--- a/weixin-java-cp/pom.xml
+++ b/weixin-java-cp/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.3.B
+    3.4.4.B
   
 
   weixin-java-cp
diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml
index fbe2dfc74f..c1e270b52d 100644
--- a/weixin-java-miniapp/pom.xml
+++ b/weixin-java-miniapp/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.3.B
+    3.4.4.B
   
 
   weixin-java-miniapp
diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml
index 454abd3ea6..37db924e04 100644
--- a/weixin-java-mp/pom.xml
+++ b/weixin-java-mp/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.3.B
+    3.4.4.B
   
 
   weixin-java-mp
diff --git a/weixin-java-open/pom.xml b/weixin-java-open/pom.xml
index 7dbb76e51d..e1fc0c0839 100644
--- a/weixin-java-open/pom.xml
+++ b/weixin-java-open/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.3.B
+    3.4.4.B
   
 
   weixin-java-open
diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml
index ae87556be8..e3507fc5a5 100644
--- a/weixin-java-pay/pom.xml
+++ b/weixin-java-pay/pom.xml
@@ -5,7 +5,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.3.B
+    3.4.4.B
   
   4.0.0
 

From 46f5916faae7e5d9b38f7b91802a957a6190fd48 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Mon, 17 Jun 2019 00:06:25 +0800
Subject: [PATCH 26/74] Update .travis.yml

---
 .travis.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index 6910a67e18..0c34617d15 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,7 +7,7 @@ language: java
 #      secure: "834110c7191f97ecb226970c46dcaff8e681da5a"
 
 jdk:
-  - oraclejdk8
+  - oraclejdk9
 script: "mvn clean package -DskipTests=true -Dcheckstyle.skip=true"
 
 #script:

From 26eec2c52a2f460be60089b1c93d4a6196cc8ffa Mon Sep 17 00:00:00 2001
From: Patrickcai 
Date: Tue, 18 Jun 2019 16:54:27 +0800
Subject: [PATCH 27/74] =?UTF-8?q?#1077=20=E4=BF=AE=E5=A4=8D=E5=BC=80?=
 =?UTF-8?q?=E5=8F=91=E5=B9=B3=E5=8F=B0=E5=88=A0=E9=99=A4=E7=B1=BB=E7=9B=AE?=
 =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E4=B8=AD=E6=8B=BC=E5=86=99=E9=94=99=E8=AF=AF?=
 =?UTF-8?q?=E7=9A=84second=E5=8F=82=E6=95=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=21528465979XX32V&token=&lang=zh_CN
---
 .../chanjar/weixin/open/api/impl/WxOpenFastMaServiceImpl.java   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenFastMaServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenFastMaServiceImpl.java
index 1314f37f44..e72fb02b36 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenFastMaServiceImpl.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenFastMaServiceImpl.java
@@ -208,7 +208,7 @@ public WxOpenResult addCategory (List categoryList) throws WxE
   public WxOpenResult deleteCategory (int first, int second) throws WxErrorException {
     JsonObject params = new JsonObject ();
     params.addProperty ("first", first);
-    params.addProperty ("Second", second);
+    params.addProperty ("second", second);
     String response = post (OPEN_DELETE_CATEGORY, GSON.toJson (params));
     return WxOpenGsonBuilder.create ().fromJson (response, WxOpenResult.class);
   }

From b2cf45297de503e360d92aaa598fe8b41133d476 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Tue, 18 Jun 2019 17:27:21 +0800
Subject: [PATCH 28/74] Update .travis.yml

---
 .travis.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index 0c34617d15..02fca64132 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,7 +7,7 @@ language: java
 #      secure: "834110c7191f97ecb226970c46dcaff8e681da5a"
 
 jdk:
-  - oraclejdk9
+  - openjdk8
 script: "mvn clean package -DskipTests=true -Dcheckstyle.skip=true"
 
 #script:

From 90b5ca56c2704f611481441a590c5a5596ac064a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9B=B9=E7=A5=96=E9=B9=8F?= 
Date: Tue, 18 Jun 2019 18:01:38 +0800
Subject: [PATCH 29/74] =?UTF-8?q?#1078=20=E5=AE=8C=E5=96=84=E4=BC=81?=
 =?UTF-8?q?=E4=B8=9A=E5=BE=AE=E4=BF=A1=E5=A4=96=E9=83=A8=E8=81=94=E7=B3=BB?=
 =?UTF-8?q?=E4=BA=BA=E7=9B=B8=E5=85=B3=E6=8E=A5=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

- 完成ExternalContact基础三个接口
- 外部联系人变更事件的消息解析
- 外部联系人的属性,增加标记公司名称和标记电话号码,还有tag分类
- 企业微信API url修改优化
---
 .../cp/api/WxCpExternalContactService.java    | 58 +++++++++++++++++++
 .../me/chanjar/weixin/cp/api/WxCpService.java |  4 +-
 .../weixin/cp/api/WxCpUserService.java        |  2 +
 .../cp/api/impl/BaseWxCpServiceImpl.java      | 18 +++---
 .../impl/WxCpExternalContactServiceImpl.java  | 41 +++++++++++++
 .../cp/bean/WxCpUserExternalContactInfo.java  | 28 ++++++---
 .../cp/bean/WxCpUserExternalContactList.java  | 58 +++++++++++++++++++
 .../bean/WxCpUserWithExternalPermission.java  | 49 ++++++++++++++++
 .../weixin/cp/bean/WxCpXmlMessage.java        | 20 +++++++
 .../weixin/cp/constant/WxCpApiPathConsts.java |  6 ++
 .../weixin/cp/constant/WxCpConsts.java        | 20 +++++++
 .../chanjar/weixin/cp/api/ApiTestModule.java  | 12 ++++
 .../WxCpExternalContactServiceImplTest.java   | 45 ++++++++++++++
 .../cp/api/impl/WxCpUserServiceImplTest.java  |  9 +--
 .../weixin/cp/bean/WxCpXmlMessageTest.java    | 51 +++++++++++++++-
 15 files changed, 393 insertions(+), 28 deletions(-)
 create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java
 create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java
 create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactList.java
 create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserWithExternalPermission.java
 create mode 100644 weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java

diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java
new file mode 100644
index 0000000000..92f2258696
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java
@@ -0,0 +1,58 @@
+package me.chanjar.weixin.cp.api;
+
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.cp.bean.WxCpUserExternalContactInfo;
+
+import java.util.List;
+
+/**
+ * 
+ * 外部联系人管理接口,企业微信的外部联系人的接口和通讯录接口已经拆离
+ *  Created by Joe Cao on 2019/6/14
+ * 
+ * + * @author JoeCao + */ +public interface WxCpExternalContactService { + /** + * 获取外部联系人详情. + *
+   *   企业可通过此接口,根据外部联系人的userid,拉取外部联系人详情。权限说明:
+   * 企业需要使用外部联系人管理secret所获取的accesstoken来调用
+   * 第三方应用需拥有“企业客户”权限。
+   * 第三方应用调用时,返回的跟进人follow_user仅包含应用可见范围之内的成员。
+   * 
+ * + * @param userId 外部联系人的userid + */ + WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException; + + /** + * 获取外部联系人列表. + *
+   *   企业可通过此接口获取指定成员添加的客户列表。
+   *   客户是指配置了客户联系功能的成员所添加的外部联系人。
+   *   没有配置客户联系功能的成员,所添加的外部联系人将不会作为客户返回。
+   * 第三方应用需拥有“企业客户”权限。
+   * 第三方应用调用时,返回的跟进人follow_user仅包含应用可见范围之内的成员。
+   * 
+ * + * @param userId 外部联系人的userid + * @return List of External wx id + */ + List listExternalContacts(String userId) throws WxErrorException; + + + /** + * 企业和第三方服务商可通过此接口获取配置了客户联系功能的成员(Customer Contact)列表。 + *
+   *   企业需要使用外部联系人管理secret所获取的accesstoken来调用(accesstoken如何获取?);
+   *   第三方应用需拥有“企业客户”权限。
+   *   第三方应用只能获取到可见范围内的配置了客户联系功能的成员
+   * 
+ * + * @return List of CpUser id + */ + List listFollowUser() throws WxErrorException; + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java index aeb7ff0956..e25fd63c25 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java @@ -284,7 +284,9 @@ public interface WxCpService { * 获取用户相关接口的服务类对象 */ WxCpUserService getUserService(); - + + WxCpExternalContactService getExternalContactService(); + /** * 获取群聊服务 * 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 4561ecb35c..544cfb8e9b 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 @@ -149,4 +149,6 @@ public interface WxCpUserService { * @param userId 外部联系人的userid */ WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException; + + } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java index 9db88b7c0e..c7f10f6b30 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java @@ -19,17 +19,7 @@ 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.cp.api.WxCpAgentService; -import me.chanjar.weixin.cp.api.WxCpChatService; -import me.chanjar.weixin.cp.api.WxCpDepartmentService; -import me.chanjar.weixin.cp.api.WxCpMediaService; -import me.chanjar.weixin.cp.api.WxCpMenuService; -import me.chanjar.weixin.cp.api.WxCpOAuth2Service; -import me.chanjar.weixin.cp.api.WxCpOaService; -import me.chanjar.weixin.cp.api.WxCpService; -import me.chanjar.weixin.cp.api.WxCpTagService; -import me.chanjar.weixin.cp.api.WxCpTaskCardService; -import me.chanjar.weixin.cp.api.WxCpUserService; +import me.chanjar.weixin.cp.api.*; import me.chanjar.weixin.cp.bean.WxCpMaJsCode2SessionResult; import me.chanjar.weixin.cp.bean.WxCpMessage; import me.chanjar.weixin.cp.bean.WxCpMessageSendResult; @@ -60,6 +50,7 @@ public abstract class BaseWxCpServiceImpl implements WxCpService, RequestH private WxCpAgentService agentService = new WxCpAgentServiceImpl(this); private WxCpOaService oaService = new WxCpOaServiceImpl(this); private WxCpTaskCardService taskCardService = new WxCpTaskCardServiceImpl(this); + private WxCpExternalContactService externalContactService = new WxCpExternalContactServiceImpl(this); /** * 全局的是否正在刷新access token的锁 @@ -396,6 +387,11 @@ public WxCpUserService getUserService() { return userService; } + @Override + public WxCpExternalContactService getExternalContactService() { + return externalContactService; + } + @Override public WxCpChatService getChatService() { return chatService; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java new file mode 100644 index 0000000000..1891000839 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java @@ -0,0 +1,41 @@ +package me.chanjar.weixin.cp.api.impl; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.cp.api.WxCpExternalContactService; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.WxCpUserExternalContactInfo; +import me.chanjar.weixin.cp.bean.WxCpUserExternalContactList; +import me.chanjar.weixin.cp.bean.WxCpUserWithExternalPermission; + +import java.util.List; + +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.ExternalContact.*; + +public class WxCpExternalContactServiceImpl implements WxCpExternalContactService { + private WxCpService mainService; + + public WxCpExternalContactServiceImpl(WxCpService mainService) { + this.mainService = mainService; + } + + @Override + public WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException { + String responseContent = this.mainService.get(this.mainService.getWxCpConfigStorage().getApiUrl(GET_EXTERNAL_CONTACT + userId), null); + + return WxCpUserExternalContactInfo.fromJson(responseContent); + } + + @Override + public List listExternalContacts(String userId) throws WxErrorException { + String responseContent = this.mainService.get(this.mainService.getWxCpConfigStorage().getApiUrl(LIST_EXTERNAL_CONTACT + userId), null); + WxCpUserExternalContactList list = WxCpUserExternalContactList.fromJson(responseContent); + return list.getExternalUserId(); + } + + @Override + public List listFollowUser() throws WxErrorException { + String responseContent = this.mainService.get(this.mainService.getWxCpConfigStorage().getApiUrl(GET_FOLLOW_USER_LIST), null); + WxCpUserWithExternalPermission list = WxCpUserWithExternalPermission.fromJson(responseContent); + return list.getFollowUser(); + } +} 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 index 466eac4a6e..d099e4eeb6 100644 --- 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 @@ -1,16 +1,11 @@ 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 lombok.*; import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; +import java.util.List; + /** *
  * 外部联系人详情
@@ -118,9 +113,26 @@ public static class FollowedUser {
     private String description;
     @SerializedName("createtime")
     private Long createTime;
+    private String state;
+    @SerializedName("remark_company")
+    private String remarkCompany;
+    @SerializedName("remark_mobiles")
+    private String[] remarkMobiles;
+    private Tag[] tags;
+
   }
 
   public static WxCpUserExternalContactInfo fromJson(String json) {
     return WxCpGsonBuilder.create().fromJson(json, WxCpUserExternalContactInfo.class);
   }
+
+  @Setter
+  @Getter
+  public static class Tag {
+    @SerializedName("group_name")
+    private String groupName;
+    @SerializedName("tag_name")
+    private String tagName;
+    private int type;
+  }
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactList.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactList.java
new file mode 100644
index 0000000000..25e42ffc4a
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactList.java
@@ -0,0 +1,58 @@
+package me.chanjar.weixin.cp.bean;
+
+import com.google.gson.annotations.Expose;
+import com.google.gson.annotations.SerializedName;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+import java.util.List;
+
+/**
+ * 
+ * 外部联系人列表
+ * Created by Joe Cao on 2019/6/16.
+ * 参考文档:https://work.weixin.qq.com/api/doc#90001/90143/91570
+ * 
+ * + * @author Joe Cao + */ +public class WxCpUserExternalContactList { + @SerializedName("errcode") + @Expose + private Long errcode; + @SerializedName("errmsg") + @Expose + private String errmsg; + + @SerializedName("external_userid") + @Expose + private List externalUserId = null; + + public Long getErrcode() { + return errcode; + } + + public void setErrcode(Long errcode) { + this.errcode = errcode; + } + + public String getErrmsg() { + return errmsg; + } + + public void setErrmsg(String errmsg) { + this.errmsg = errmsg; + } + + + public List getExternalUserId() { + return externalUserId; + } + + public void setExternalUserId(List externalUserId) { + this.externalUserId = externalUserId; + } + + public static WxCpUserExternalContactList fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpUserExternalContactList.class); + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserWithExternalPermission.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserWithExternalPermission.java new file mode 100644 index 0000000000..2530c79dc8 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserWithExternalPermission.java @@ -0,0 +1,49 @@ +package me.chanjar.weixin.cp.bean; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.util.List; + +public class WxCpUserWithExternalPermission { + @SerializedName("errcode") + @Expose + private Long errcode; + @SerializedName("errmsg") + @Expose + private String errmsg; + + @SerializedName("follow_user") + @Expose + private List followUser = null; + + public Long getErrcode() { + return errcode; + } + + public void setErrcode(Long errcode) { + this.errcode = errcode; + } + + public String getErrmsg() { + return errmsg; + } + + public void setErrmsg(String errmsg) { + this.errmsg = errmsg; + } + + public List getFollowUser() { + return followUser; + } + + public void setFollowUser(List followUser) { + this.followUser = followUser; + } + + + public static WxCpUserWithExternalPermission fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpUserWithExternalPermission.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 72f63b5dda..c201af5cb6 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 @@ -175,6 +175,26 @@ public class WxCpXmlMessage implements Serializable { @XStreamConverter(value = XStreamCDataConverter.class) private String userId; + /** + * 变更信息的外部联系人的userid,注意不是企业成员的帐号. + */ + @XStreamAlias("ExternalUserID") + @XStreamConverter(value = XStreamCDataConverter.class) + private String externalUserID; + + /** + * 添加此用户的「联系我」方式配置的state参数,可用于识别添加此用户的渠道 + */ + @XStreamAlias("State") + @XStreamConverter(value = XStreamCDataConverter.class) + private String state; + + /** + * 欢迎语code,可用于发送欢迎语 + */ + @XStreamAlias("WelcomeCode") + @XStreamConverter(value = XStreamCDataConverter.class) + private String welcomeCode; /** * 新的UserID,变更时推送(userid由系统生成时可更改一次). */ diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java index 9e1294db5c..61c3459f02 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java @@ -103,4 +103,10 @@ public static class User { public static final String USER_CONVERT_TO_USERID = "/cgi-bin/user/convert_to_userid"; public static final String GET_EXTERNAL_CONTACT = "/cgi-bin/crm/get_external_contact?external_userid="; } + + public static class ExternalContact { + public static final String GET_EXTERNAL_CONTACT = "/cgi-bin/crm/get_external_contact?external_userid="; + public static final String LIST_EXTERNAL_CONTACT = "/cgi-bin/externalcontact/list?userid="; + public static final String GET_FOLLOW_USER_LIST = "/cgi-bin/externalcontact/get_follow_user_list"; + } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java index b3809ad0c3..aa4eded451 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java @@ -89,6 +89,26 @@ public static class EventType { */ public static final String TASKCARD_CLICK = "taskcard_click"; + /** + * 企业成员添加外部联系人事件推送 + */ + public static final String CHANGE_EXTERNAL_CONTACT = "change_external_contact"; + + + } + + /** + * 企业外部联系人变更事件的CHANGE_TYPE + */ + public static class ExternalContactChangeType { + /** + * 新增外部联系人 + */ + public static final String ADD_EXTERNAL_CONTACT = "add_external_contact"; + /** + * 删除外部联系人 + */ + public static final String DEL_EXTERNAL_CONTACT = "del_external_contact"; } /** diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java index c87b6455ac..5ef750f89a 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java @@ -52,6 +52,8 @@ public static class WxXmlCpInMemoryConfigStorage extends WxCpInMemoryConfigStora protected String tagId; + protected String externalUserId; + public String getUserId() { return this.userId; } @@ -76,12 +78,22 @@ public void setTagId(String tagId) { this.tagId = tagId; } + public String getExternalUserId() { + return externalUserId; + } + + public void setExternalUserId(String externalUserId) { + this.externalUserId = externalUserId; + } + @Override public String toString() { return super.toString() + " > WxXmlCpConfigStorage{" + "userId='" + this.userId + '\'' + ", departmentId='" + this.departmentId + '\'' + ", tagId='" + this.tagId + '\'' + + ", externalUserId='" + this.externalUserId + '\'' + + '}'; } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java new file mode 100644 index 0000000000..d39fd6e493 --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java @@ -0,0 +1,45 @@ +package me.chanjar.weixin.cp.api.impl; + +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.WxCpUserExternalContactInfo; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.util.List; + +import static org.testng.Assert.assertNotNull; + +@Guice(modules = ApiTestModule.class) +public class WxCpExternalContactServiceImplTest { + @Inject + private WxCpService wxCpService; + @Inject + protected ApiTestModule.WxXmlCpInMemoryConfigStorage configStorage; + private String userId = "someone" + System.currentTimeMillis(); + + @Test + public void testGetExternalContact() throws WxErrorException { + String externalUserId = this.configStorage.getExternalUserId(); + WxCpUserExternalContactInfo result = this.wxCpService.getExternalContactService().getExternalContact(externalUserId); + System.out.println(result); + assertNotNull(result); + } + + @Test + public void testListExternalContacts() throws WxErrorException { + String userId = this.configStorage.getUserId(); + List ret = this.wxCpService.getExternalContactService().listExternalContacts(userId); + System.out.println(ret); + assertNotNull(ret); + } + + @Test + public void testListExternalWithPermission() throws WxErrorException { + List ret = this.wxCpService.getExternalContactService().listFollowUser(); + System.out.println(ret); + assertNotNull(ret); + } +} 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 2ec33e7ba7..6b88876fbb 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 @@ -93,7 +93,7 @@ public void testListSimpleByDepartment() throws Exception { @Test public void testInvite() throws Exception { WxCpInviteResult result = this.wxCpService.getUserService().invite( - Lists.newArrayList(userId), null,null); + Lists.newArrayList(userId), null, null); System.out.println(result); } @@ -111,10 +111,5 @@ public void testOpenid2UserId() throws Exception { 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/WxCpXmlMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java index 11a2dbe469..ad9a04b610 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java @@ -1,6 +1,7 @@ package me.chanjar.weixin.cp.bean; import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.cp.constant.WxCpConsts; import org.testng.annotations.Test; import static me.chanjar.weixin.cp.constant.WxCpConsts.EventType.TASKCARD_CLICK; @@ -106,7 +107,7 @@ public void testSendPicsInfo() { "2" + "" + ""; - WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml.replace("","")); + WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml.replace("", "")); assertEquals(wxMessage.getToUserName(), "wx45a0972125658be9"); assertEquals(wxMessage.getFromUserName(), "xiaohe"); assertEquals(wxMessage.getCreateTime(), new Long(1502012364L)); @@ -173,4 +174,52 @@ public void testTaskCardEvent() { assertEquals(wxMessage.getEventKey(), "key111"); assertEquals(wxMessage.getTaskId(), "taskid111"); } + + public void testAddExternalUserEvent() { + String xml = "" + + "" + + "" + + "1403610513" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""; + WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml); + assertEquals(wxMessage.getToUserName(), "toUser"); + assertEquals(wxMessage.getFromUserName(), "sys"); + assertEquals(wxMessage.getCreateTime(), Long.valueOf(1403610513L)); + assertEquals(wxMessage.getMsgType(), WxConsts.XmlMsgType.EVENT); + assertEquals(wxMessage.getEvent(), WxCpConsts.EventType.CHANGE_EXTERNAL_CONTACT); + assertEquals(wxMessage.getChangeType(), WxCpConsts.ExternalContactChangeType.ADD_EXTERNAL_CONTACT); + assertEquals(wxMessage.getExternalUserID(), "woAJ2GCAAAXtWyujaWJHDDGi0mACH71w"); + assertEquals(wxMessage.getState(), "teststate"); + assertEquals(wxMessage.getWelcomeCode(), "WELCOMECODE"); + + } + + public void testDelExternalUserEvent() { + String xml = "" + + "" + + "" + + "1403610513" + + "" + + "" + + "" + + "" + + "" + + ""; + WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml); + assertEquals(wxMessage.getToUserName(), "toUser"); + assertEquals(wxMessage.getFromUserName(), "sys"); + assertEquals(wxMessage.getCreateTime(), Long.valueOf(1403610513L)); + assertEquals(wxMessage.getMsgType(), WxConsts.XmlMsgType.EVENT); + assertEquals(wxMessage.getEvent(), WxCpConsts.EventType.CHANGE_EXTERNAL_CONTACT); + assertEquals(wxMessage.getChangeType(), WxCpConsts.ExternalContactChangeType.DEL_EXTERNAL_CONTACT); + assertEquals(wxMessage.getUserId(), "zhangsan"); + assertEquals(wxMessage.getExternalUserID(), "woAJ2GCAAAXtWyujaWJHDDGi0mACH71w"); + } } From 18e3f7502831208ece1e79d0ddeeaea6f2b79e1e Mon Sep 17 00:00:00 2001 From: RobinGao <315789501@qq.com> Date: Fri, 21 Jun 2019 13:57:13 +0800 Subject: [PATCH 30/74] =?UTF-8?q?#1081=20=E5=BC=80=E6=94=BE=E5=B9=B3?= =?UTF-8?q?=E5=8F=B0=E6=A8=A1=E5=9D=97=E5=A2=9E=E5=8A=A0=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E6=89=80=E6=9C=89=E6=8E=88=E6=9D=83=E6=96=B9=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../open/api/WxOpenComponentService.java | 11 +++-- .../api/impl/WxOpenComponentServiceImpl.java | 20 +++++++-- .../result/WxOpenAuthorizerListResult.java | 15 +++++++ ...WxOpenAuthorizerListResultGsonAdapter.java | 41 +++++++++++++++++++ .../open/util/json/WxOpenGsonBuilder.java | 7 +--- 5 files changed, 81 insertions(+), 13 deletions(-) create mode 100644 weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenAuthorizerListResult.java create mode 100644 weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenAuthorizerListResultGsonAdapter.java 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 4b2ddbc412..2beec638f8 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 @@ -7,10 +7,7 @@ import me.chanjar.weixin.open.bean.WxOpenCreateResult; import me.chanjar.weixin.open.bean.WxOpenMaCodeTemplate; import me.chanjar.weixin.open.bean.message.WxOpenXmlMessage; -import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerInfoResult; -import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerOptionResult; -import me.chanjar.weixin.open.bean.result.WxOpenQueryAuthResult; -import me.chanjar.weixin.open.bean.result.WxOpenResult; +import me.chanjar.weixin.open.bean.result.*; import java.util.List; @@ -25,6 +22,7 @@ public interface WxOpenComponentService { String API_GET_AUTHORIZER_INFO_URL = "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info"; String API_GET_AUTHORIZER_OPTION_URL = "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_option"; String API_SET_AUTHORIZER_OPTION_URL = "https://api.weixin.qq.com/cgi-bin/component/api_set_authorizer_option"; + String API_GET_AUTHORIZER_LIST = "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_list?component_access_token=%s"; String COMPONENT_LOGIN_PAGE_URL = "https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid=%s&pre_auth_code=%s&redirect_uri=%s&auth_type=xxx&biz_appid=xxx"; @@ -126,6 +124,11 @@ public interface WxOpenComponentService { */ WxOpenAuthorizerOptionResult getAuthorizerOption(String authorizerAppid, String optionName) throws WxErrorException; + /** + * 获取所有授权方列表 + */ + WxOpenAuthorizerListResult getAuthorizerList(int begin, int len) 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 319e12ffa2..5b71c78393 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 @@ -18,10 +18,7 @@ import me.chanjar.weixin.open.bean.WxOpenMaCodeTemplate; import me.chanjar.weixin.open.bean.auth.WxOpenAuthorizationInfo; import me.chanjar.weixin.open.bean.message.WxOpenXmlMessage; -import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerInfoResult; -import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerOptionResult; -import me.chanjar.weixin.open.bean.result.WxOpenQueryAuthResult; -import me.chanjar.weixin.open.bean.result.WxOpenResult; +import me.chanjar.weixin.open.bean.result.*; import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -304,6 +301,21 @@ public WxOpenAuthorizerInfoResult getAuthorizerInfo(String authorizerAppid) thro return WxOpenGsonBuilder.create().fromJson(responseContent, WxOpenAuthorizerInfoResult.class); } + @Override + public WxOpenAuthorizerListResult getAuthorizerList(int begin, int len) throws WxErrorException { + + String url = String.format(API_GET_AUTHORIZER_LIST, getComponentAccessToken(false)); + begin = begin < 0 ? 0 : begin; + len = len == 0 ? 10 : len; + + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("component_appid", getWxOpenConfigStorage().getComponentAppId()); + jsonObject.addProperty("offset", begin); + jsonObject.addProperty("count", len); + String responseContent = post(url, jsonObject.toString()); + return WxOpenGsonBuilder.create().fromJson(responseContent, WxOpenAuthorizerListResult.class); + } + @Override public WxOpenAuthorizerOptionResult getAuthorizerOption(String authorizerAppid, String optionName) throws WxErrorException { JsonObject jsonObject = new JsonObject(); diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenAuthorizerListResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenAuthorizerListResult.java new file mode 100644 index 0000000000..afe9ea9403 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenAuthorizerListResult.java @@ -0,0 +1,15 @@ +package me.chanjar.weixin.open.bean.result; + +import lombok.Data; + +import java.util.List; +import java.util.Map; + +/** + * @author robgao + */ +@Data +public class WxOpenAuthorizerListResult { + private int totalCount; + private List> list; +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenAuthorizerListResultGsonAdapter.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenAuthorizerListResultGsonAdapter.java new file mode 100644 index 0000000000..38faf2ff18 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenAuthorizerListResultGsonAdapter.java @@ -0,0 +1,41 @@ +package me.chanjar.weixin.open.util.json; + +import com.google.gson.*; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerListResult; + +import java.lang.reflect.Type; +import java.util.*; + +/** + * @author robgao + * @Email 315789501@qq.com + */ +public class WxOpenAuthorizerListResultGsonAdapter implements JsonDeserializer { + + private static final String AUTHORIZER_APPID="authorizer_appid"; + private static final String REFRESH_TOKEN="refresh_token"; + private static final String AUTH_TIME="auth_time"; + @Override + public WxOpenAuthorizerListResult deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { + JsonObject jsonObject = jsonElement.getAsJsonObject(); + + WxOpenAuthorizerListResult wxOpenAuthorizerListResult= new WxOpenAuthorizerListResult(); + wxOpenAuthorizerListResult.setTotalCount(GsonHelper.getInteger(jsonObject, "total_count").intValue()); + + List> list = new ArrayList<>(); + Iterator jsonElementIterator = jsonObject.getAsJsonArray("list").iterator(); + + while(jsonElementIterator.hasNext()){ + JsonObject authorizer = jsonElementIterator.next().getAsJsonObject(); + Map authorizerMap = new HashMap<>(10); + + authorizerMap.put(AUTHORIZER_APPID, GsonHelper.getString(authorizer,AUTHORIZER_APPID)); + authorizerMap.put(REFRESH_TOKEN, GsonHelper.getString(authorizer,REFRESH_TOKEN)); + authorizerMap.put(AUTH_TIME, GsonHelper.getString(authorizer,AUTH_TIME)); + list.add(authorizerMap); + } + wxOpenAuthorizerListResult.setList(list); + return wxOpenAuthorizerListResult; + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenGsonBuilder.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenGsonBuilder.java index 10c2911df2..f28178f673 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenGsonBuilder.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenGsonBuilder.java @@ -6,10 +6,7 @@ import me.chanjar.weixin.open.bean.WxOpenComponentAccessToken; import me.chanjar.weixin.open.bean.auth.WxOpenAuthorizationInfo; import me.chanjar.weixin.open.bean.auth.WxOpenAuthorizerInfo; -import me.chanjar.weixin.open.bean.result.WxFastMaAccountBasicInfoResult; -import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerInfoResult; -import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerOptionResult; -import me.chanjar.weixin.open.bean.result.WxOpenQueryAuthResult; +import me.chanjar.weixin.open.bean.result.*; /** * @author 007 @@ -27,8 +24,8 @@ public class WxOpenGsonBuilder { INSTANCE.registerTypeAdapter(WxOpenQueryAuthResult.class, new WxOpenQueryAuthResultGsonAdapter()); INSTANCE.registerTypeAdapter(WxOpenAuthorizerInfoResult.class, new WxOpenAuthorizerInfoResultGsonAdapter()); INSTANCE.registerTypeAdapter(WxOpenAuthorizerOptionResult.class, new WxOpenAuthorizerOptionResultGsonAdapter()); - INSTANCE.registerTypeAdapter(WxFastMaAccountBasicInfoResult.class, new WxFastMaAccountBasicInfoGsonAdapter ()); + INSTANCE.registerTypeAdapter(WxOpenAuthorizerListResult.class, new WxOpenAuthorizerListResultGsonAdapter ()); } From a63321f712140896bd317bd17a137d0f260a0486 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 22 Jun 2019 16:48:34 +0800 Subject: [PATCH 31/74] =?UTF-8?q?=E8=A7=84=E8=8C=83=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chanjar/weixin/mp/api/WxMpMessageHandler.java | 11 +++++++---- .../chanjar/weixin/mp/api/WxMpMessageRouter.java | 8 ++++---- .../me/chanjar/weixin/mp/demo/WxMpDemoServer.java | 14 +++++--------- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageHandler.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageHandler.java index 474e3e6950..0c6912c38d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageHandler.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageHandler.java @@ -8,18 +8,21 @@ import java.util.Map; /** - * 处理微信推送消息的处理器接口 + * 处理微信推送消息的处理器接口. * * @author Daniel Qian */ public interface WxMpMessageHandler { /** - * @param wxMessage + * 处理微信推送消息. + * + * @param wxMessage 微信推送消息 * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 - * @param wxMpService - * @param sessionManager + * @param wxMpService 服务类 + * @param sessionManager session管理器 * @return xml格式的消息,如果在异步规则里处理的话,可以返回null + * @throws WxErrorException 异常 */ WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java index e85a2b65cb..86351e5acc 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java @@ -144,21 +144,21 @@ List getRules() { } /** - * 开始一个新的Route规则 + * 开始一个新的Route规则. */ public WxMpMessageRouterRule rule() { return new WxMpMessageRouterRule(this); } /** - * 处理微信消息 + * 处理微信消息. */ public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage, final Map context) { return route(wxMessage, context, null); } /** - * 处理微信消息 + * 处理微信消息. */ public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage, final Map context, WxMpService wxMpService) { if (wxMpService == null) { @@ -252,7 +252,7 @@ protected boolean isMsgDuplicated(WxMpXmlMessage wxMessage) { } /** - * 对session的访问结束 + * 对session的访问结束. */ protected void sessionEndAccess(WxMpXmlMessage wxMessage) { diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java index d2f4fde881..5d85d64c05 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java @@ -27,13 +27,11 @@ public static void main(String[] args) throws Exception { ServletHandler servletHandler = new ServletHandler(); server.setHandler(servletHandler); - ServletHolder endpointServletHolder = new ServletHolder( - new WxMpEndpointServlet(wxMpConfigStorage, wxMpService, - wxMpMessageRouter)); + ServletHolder endpointServletHolder = new ServletHolder(new WxMpEndpointServlet(wxMpConfigStorage, wxMpService, + wxMpMessageRouter)); servletHandler.addServletWithMapping(endpointServletHolder, "/*"); - ServletHolder oauthServletHolder = new ServletHolder( - new WxMpOAuth2Servlet(wxMpService)); + ServletHolder oauthServletHolder = new ServletHolder(new WxMpOAuth2Servlet(wxMpService)); servletHandler.addServletWithMapping(oauthServletHolder, "/oauth2/*"); server.start(); @@ -41,10 +39,8 @@ public static void main(String[] args) throws Exception { } private static void initWeixin() { - try (InputStream is1 = ClassLoader - .getSystemResourceAsStream("test-config.xml")) { - WxMpDemoInMemoryConfigStorage config = WxMpDemoInMemoryConfigStorage - .fromXml(is1); + try (InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml")) { + WxMpDemoInMemoryConfigStorage config = WxMpDemoInMemoryConfigStorage.fromXml(is1); wxMpConfigStorage = config; wxMpService = new WxMpServiceHttpClientImpl(); From 54c8ae54520524544eb5d17650949c10fb4c243a Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 22 Jun 2019 16:50:31 +0800 Subject: [PATCH 32/74] =?UTF-8?q?#1079=20=E5=B0=8F=E7=A8=8B=E5=BA=8F?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AF=B9=E8=BD=AC=E5=8F=91=E5=AE=A2=E6=9C=8D?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E5=8A=9F=E8=83=BD=E7=9A=84=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../miniapp/message/WxMaMessageHandler.java | 17 ++++-- .../message/WxMaMessageInterceptor.java | 10 ++- .../miniapp/message/WxMaMessageMatcher.java | 7 ++- .../wx/miniapp/message/WxMaMessageRouter.java | 35 ++++------- .../message/WxMaMessageRouterRule.java | 42 +++++++------ .../wx/miniapp/message/WxMaXmlOutMessage.java | 60 ++++++++++++++++++ .../wx/miniapp/demo/WxMaDemoServer.java | 61 ++++++++++++------- .../wx/miniapp/demo/WxMaPortalServlet.java | 37 ++++++----- 8 files changed, 179 insertions(+), 90 deletions(-) create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaXmlOutMessage.java diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageHandler.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageHandler.java index f60edc1d8a..9fdd956934 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageHandler.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageHandler.java @@ -8,13 +8,22 @@ import java.util.Map; /** - * 处理小程序推送消息的处理器接口 + * 处理小程序推送消息的处理器接口. * * @author Binary Wang */ public interface WxMaMessageHandler { - - void handle(WxMaMessage message, Map context, - WxMaService service, WxSessionManager sessionManager) throws WxErrorException; + /** + * 处理消息. + * + * @param message 输入消息 + * @param context 上下文 + * @param service 服务类 + * @param sessionManager session管理器 + * @return 输出消息 + * @throws WxErrorException 异常 + */ + WxMaXmlOutMessage handle(WxMaMessage message, Map context, + WxMaService service, WxSessionManager sessionManager) throws WxErrorException; } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageInterceptor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageInterceptor.java index ef0d500a19..31600a231b 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageInterceptor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageInterceptor.java @@ -8,17 +8,21 @@ import java.util.Map; /** - * 微信消息拦截器,可以用来做验证 + * 微信消息拦截器,可以用来做验证. * * @author Binary Wang */ public interface WxMaMessageInterceptor { /** - * 拦截微信消息 + * 拦截微信消息. * - * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 + * @param wxMessage . + * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 + * @param wxMaService . + * @param sessionManager . * @return true代表OK,false代表不OK + * @throws WxErrorException . */ boolean intercept(WxMaMessage wxMessage, Map context, diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageMatcher.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageMatcher.java index 9d4e54f89b..5283713c5d 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageMatcher.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageMatcher.java @@ -3,14 +3,17 @@ import cn.binarywang.wx.miniapp.bean.WxMaMessage; /** - * 消息匹配器,用在消息路由的时候 + * 消息匹配器,用在消息路由的时候. * * @author Binary Wang */ public interface WxMaMessageMatcher { /** - * 消息是否匹配某种模式 + * 消息是否匹配某种模式. + * + * @param message 消息 + * @return 是否匹配 */ boolean match(WxMaMessage message); diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouter.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouter.java index be3af708bd..bda2e6c81e 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouter.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouter.java @@ -32,8 +32,6 @@ public class WxMaMessageRouter { private ExecutorService executorService; - private WxMessageDuplicateChecker messageDuplicateChecker; - private WxSessionManager sessionManager; private WxErrorExceptionHandler exceptionHandler; @@ -43,7 +41,6 @@ public WxMaMessageRouter(WxMaService wxMaService) { ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("WxMaMessageRouter-pool-%d").build(); this.executorService = new ThreadPoolExecutor(DEFAULT_THREAD_POOL_SIZE, DEFAULT_THREAD_POOL_SIZE, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), namedThreadFactory); - this.messageDuplicateChecker = new WxMessageInMemoryDuplicateChecker(); this.sessionManager = new StandardSessionManager(); this.exceptionHandler = new LogExceptionHandler(); } @@ -58,16 +55,6 @@ public void setExecutorService(ExecutorService executorService) { this.executorService = executorService; } - /** - *
-   * 设置自定义的 {@link me.chanjar.weixin.common.api.WxMessageDuplicateChecker}
-   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker}
-   * 
- */ - public void setMessageDuplicateChecker(WxMessageDuplicateChecker messageDuplicateChecker) { - this.messageDuplicateChecker = messageDuplicateChecker; - } - /** *
    * 设置自定义的{@link me.chanjar.weixin.common.session.WxSessionManager}
@@ -93,16 +80,16 @@ List getRules() {
   }
 
   /**
-   * 开始一个新的Route规则
+   * 开始一个新的Route规则.
    */
   public WxMaMessageRouterRule rule() {
     return new WxMaMessageRouterRule(this);
   }
 
   /**
-   * 处理微信消息
+   * 处理微信消息.
    */
-  public void route(final WxMaMessage wxMessage, final Map context) {
+  private WxMaXmlOutMessage route(final WxMaMessage wxMessage, final Map context) {
     final List matchRules = new ArrayList<>();
     // 收集匹配的规则
     for (final WxMaMessageRouterRule rule : this.rules) {
@@ -115,10 +102,11 @@ public void route(final WxMaMessage wxMessage, final Map context
     }
 
     if (matchRules.size() == 0) {
-      return;
+      return null;
     }
 
     final List> futures = new ArrayList<>();
+    WxMaXmlOutMessage result = null;
     for (final WxMaMessageRouterRule rule : matchRules) {
       // 返回最后一个非异步的rule的执行结果
       if (rule.isAsync()) {
@@ -131,7 +119,7 @@ public void run() {
           })
         );
       } else {
-        rule.service(wxMessage, context, this.wxMaService, this.sessionManager, this.exceptionHandler);
+        result = rule.service(wxMessage, context, this.wxMaService, this.sessionManager, this.exceptionHandler);
         // 在同步操作结束,session访问结束
         this.log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUser());
         sessionEndAccess(wxMessage);
@@ -155,18 +143,17 @@ public void run() {
         }
       });
     }
-
+    return result;
   }
 
-  public void route(final WxMaMessage wxMessage) {
-    this.route(wxMessage, new HashMap(2));
+  public WxMaXmlOutMessage route(final WxMaMessage wxMessage) {
+   return this.route(wxMessage, new HashMap(2));
   }
 
   /**
-   * 对session的访问结束
+   * 对session的访问结束.
    */
-  protected void sessionEndAccess(WxMaMessage wxMessage) {
-
+  private void sessionEndAccess(WxMaMessage wxMessage) {
     InternalSession session = ((InternalSessionManager) this.sessionManager).findSession(wxMessage.getFromUser());
     if (session != null) {
       session.endAccess();
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java
index 2e4906ebf1..5ea3fb8a92 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java
@@ -16,7 +16,6 @@
  * @author Binary Wang
  */
 public class WxMaMessageRouterRule {
-
   private final WxMaMessageRouter routerBuilder;
 
   private boolean async = true;
@@ -46,7 +45,7 @@ public WxMaMessageRouterRule(WxMaMessageRouter routerBuilder) {
   }
 
   /**
-   * 设置是否异步执行,默认是true
+   * 设置是否异步执行,默认是true.
    */
   public WxMaMessageRouterRule async(boolean async) {
     this.async = async;
@@ -54,7 +53,7 @@ public WxMaMessageRouterRule async(boolean async) {
   }
 
   /**
-   * 如果msgType等于某值
+   * 如果msgType等于某值.
    */
   public WxMaMessageRouterRule msgType(String msgType) {
     this.msgType = msgType;
@@ -62,7 +61,7 @@ public WxMaMessageRouterRule msgType(String msgType) {
   }
 
   /**
-   * 如果event等于某值
+   * 如果event等于某值.
    */
   public WxMaMessageRouterRule event(String event) {
     this.event = event;
@@ -70,7 +69,7 @@ public WxMaMessageRouterRule event(String event) {
   }
 
   /**
-   * 如果eventKey等于某值
+   * 如果eventKey等于某值.
    */
   public WxMaMessageRouterRule eventKey(String eventKey) {
     this.eventKey = eventKey;
@@ -78,7 +77,7 @@ public WxMaMessageRouterRule eventKey(String eventKey) {
   }
 
   /**
-   * 如果content等于某值
+   * 如果content等于某值.
    */
   public WxMaMessageRouterRule content(String content) {
     this.content = content;
@@ -86,7 +85,7 @@ public WxMaMessageRouterRule content(String content) {
   }
 
   /**
-   * 如果content匹配该正则表达式
+   * 如果content匹配该正则表达式.
    */
   public WxMaMessageRouterRule rContent(String regex) {
     this.rContent = regex;
@@ -94,7 +93,7 @@ public WxMaMessageRouterRule rContent(String regex) {
   }
 
   /**
-   * 如果fromUser等于某值
+   * 如果fromUser等于某值.
    */
   public WxMaMessageRouterRule fromUser(String fromUser) {
     this.fromUser = fromUser;
@@ -102,7 +101,7 @@ public WxMaMessageRouterRule fromUser(String fromUser) {
   }
 
   /**
-   * 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候
+   * 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候.
    */
   public WxMaMessageRouterRule matcher(WxMaMessageMatcher matcher) {
     this.matcher = matcher;
@@ -110,14 +109,14 @@ public WxMaMessageRouterRule matcher(WxMaMessageMatcher matcher) {
   }
 
   /**
-   * 设置微信消息拦截器
+   * 设置微信消息拦截器.
    */
   public WxMaMessageRouterRule interceptor(WxMaMessageInterceptor interceptor) {
     return interceptor(interceptor, (WxMaMessageInterceptor[]) null);
   }
 
   /**
-   * 设置微信消息拦截器
+   * 设置微信消息拦截器.
    */
   public WxMaMessageRouterRule interceptor(WxMaMessageInterceptor interceptor, WxMaMessageInterceptor... otherInterceptors) {
     this.interceptors.add(interceptor);
@@ -130,14 +129,14 @@ public WxMaMessageRouterRule interceptor(WxMaMessageInterceptor interceptor, WxM
   }
 
   /**
-   * 设置微信消息处理器
+   * 设置微信消息处理器.
    */
   public WxMaMessageRouterRule handler(WxMaMessageHandler handler) {
     return handler(handler, (WxMaMessageHandler[]) null);
   }
 
   /**
-   * 设置微信消息处理器
+   * 设置微信消息处理器.
    */
   public WxMaMessageRouterRule handler(WxMaMessageHandler handler, WxMaMessageHandler... otherHandlers) {
     this.handlers.add(handler);
@@ -150,7 +149,7 @@ public WxMaMessageRouterRule handler(WxMaMessageHandler handler, WxMaMessageHand
   }
 
   /**
-   * 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则
+   * 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则.
    */
   public WxMaMessageRouter end() {
     this.routerBuilder.getRules().add(this);
@@ -158,7 +157,7 @@ public WxMaMessageRouter end() {
   }
 
   /**
-   * 规则结束,但是消息还会进入其他规则
+   * 规则结束,但是消息还会进入其他规则.
    */
   public WxMaMessageRouter next() {
     this.reEnter = true;
@@ -166,7 +165,7 @@ public WxMaMessageRouter next() {
   }
 
   /**
-   * 将微信自定义的事件修正为不区分大小写,
+   * 将微信自定义的事件修正为不区分大小写.
    * 比如框架定义的事件常量为click,但微信传递过来的却是CLICK
    */
   protected boolean test(WxMaMessage wxMessage) {
@@ -188,9 +187,9 @@ protected boolean test(WxMaMessage wxMessage) {
   }
 
   /**
-   * 处理微信推送过来的消息
+   * 处理微信推送过来的消息.
    */
-  protected void service(WxMaMessage wxMessage,
+  protected WxMaXmlOutMessage service(WxMaMessage wxMessage,
                          Map context,
                          WxMaService wxMaService,
                          WxSessionManager sessionManager,
@@ -199,11 +198,12 @@ protected void service(WxMaMessage wxMessage,
       context = new HashMap<>(16);
     }
 
+    WxMaXmlOutMessage outMessage = null;
     try {
       // 如果拦截器不通过
       for (WxMaMessageInterceptor interceptor : this.interceptors) {
         if (!interceptor.intercept(wxMessage, context, wxMaService, sessionManager)) {
-          return;
+          return null;
         }
       }
 
@@ -213,11 +213,13 @@ protected void service(WxMaMessage wxMessage,
         if (handler == null) {
           continue;
         }
-        handler.handle(wxMessage, context, wxMaService, sessionManager);
+        outMessage = handler.handle(wxMessage, context, wxMaService, sessionManager);
       }
     } catch (WxErrorException e) {
       exceptionHandler.handle(e);
     }
+
+    return outMessage;
   }
 
   public WxMaMessageRouter getRouterBuilder() {
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaXmlOutMessage.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaXmlOutMessage.java
new file mode 100644
index 0000000000..7211e0531a
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaXmlOutMessage.java
@@ -0,0 +1,60 @@
+package cn.binarywang.wx.miniapp.message;
+
+import cn.binarywang.wx.miniapp.config.WxMaConfig;
+import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils;
+import cn.binarywang.wx.miniapp.util.xml.XStreamTransformer;
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+import com.thoughtworks.xstream.annotations.XStreamConverter;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
+
+import java.io.Serializable;
+
+/**
+ * 微信小程序输出给微信服务器的消息.
+ *
+ * @author Binary Wang
+ * @date 2019-06-22
+ */
+@Data
+@XStreamAlias("xml")
+@Accessors(chain = true)
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class WxMaXmlOutMessage implements Serializable {
+  private static final long serialVersionUID = 4241135225946919153L;
+
+  @XStreamAlias("ToUserName")
+  @XStreamConverter(value = XStreamCDataConverter.class)
+  protected String toUserName;
+
+  @XStreamAlias("FromUserName")
+  @XStreamConverter(value = XStreamCDataConverter.class)
+  protected String fromUserName;
+
+  @XStreamAlias("CreateTime")
+  protected Long createTime;
+
+  @XStreamAlias("MsgType")
+  @XStreamConverter(value = XStreamCDataConverter.class)
+  protected String msgType;
+
+  @SuppressWarnings("unchecked")
+  public String toXml() {
+    return XStreamTransformer.toXml((Class) this.getClass(), this);
+  }
+
+  /**
+   * 转换成加密的xml格式.
+   */
+  public String toEncryptedXml(WxMaConfig config) {
+    String plainXml = toXml();
+    WxMaCryptUtils pc = new WxMaCryptUtils(config);
+    return pc.encrypt(plainXml);
+  }
+}
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 fe886f4b85..89df244413 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,15 +1,5 @@
 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;
@@ -20,11 +10,23 @@
 import cn.binarywang.wx.miniapp.constant.WxMaConstants;
 import cn.binarywang.wx.miniapp.message.WxMaMessageHandler;
 import cn.binarywang.wx.miniapp.message.WxMaMessageRouter;
+import cn.binarywang.wx.miniapp.message.WxMaXmlOutMessage;
 import cn.binarywang.wx.miniapp.test.TestConfig;
 import com.google.common.collect.Lists;
+import me.chanjar.weixin.common.api.WxConsts;
 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.Calendar;
+import java.util.Map;
+import java.util.concurrent.locks.ReentrantLock;
 
 /**
  * @author Binary Wang
@@ -33,29 +35,31 @@ public class WxMaDemoServer {
 
   private static final WxMaMessageHandler logHandler = new WxMaMessageHandler() {
     @Override
-    public void handle(WxMaMessage wxMessage, Map context,
-                       WxMaService service, WxSessionManager sessionManager) throws WxErrorException {
+    public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map context,
+                                    WxMaService service, WxSessionManager sessionManager) throws WxErrorException {
       System.out.println("收到消息:" + wxMessage.toString());
       service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("收到信息为:" + wxMessage.toJson())
         .toUser(wxMessage.getFromUser()).build());
+      return null;
     }
   };
 
   private static final WxMaMessageHandler textHandler = new WxMaMessageHandler() {
     @Override
-    public void handle(WxMaMessage wxMessage, Map context,
-                       WxMaService service, WxSessionManager sessionManager)
+    public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map context,
+                                    WxMaService service, WxSessionManager sessionManager)
       throws WxErrorException {
       service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("回复文本消息")
         .toUser(wxMessage.getFromUser()).build());
+      return null;
     }
 
   };
 
   private static final WxMaMessageHandler picHandler = new WxMaMessageHandler() {
     @Override
-    public void handle(WxMaMessage wxMessage, Map context,
-                       WxMaService service, WxSessionManager sessionManager) throws WxErrorException {
+    public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map context,
+                                    WxMaService service, WxSessionManager sessionManager) throws WxErrorException {
       try {
         WxMediaUploadResult uploadResult = service.getMediaService()
           .uploadMedia(WxMaConstants.MediaType.IMAGE, "png",
@@ -69,13 +73,14 @@ public void handle(WxMaMessage wxMessage, Map context,
       } catch (WxErrorException e) {
         e.printStackTrace();
       }
+      return null;
     }
   };
 
   private static final WxMaMessageHandler qrcodeHandler = new WxMaMessageHandler() {
     @Override
-    public void handle(WxMaMessage wxMessage, Map context,
-                       WxMaService service, WxSessionManager sessionManager) throws WxErrorException {
+    public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map context,
+                                    WxMaService service, WxSessionManager sessionManager) throws WxErrorException {
       try {
         final File file = service.getQrcodeService().createQrcode("123", 430);
         WxMediaUploadResult uploadResult = service.getMediaService().uploadMedia(WxMaConstants.MediaType.IMAGE, file);
@@ -88,13 +93,14 @@ public void handle(WxMaMessage wxMessage, Map context,
       } catch (WxErrorException e) {
         e.printStackTrace();
       }
+      return null;
     }
   };
 
   private static final WxMaMessageHandler templateMsgHandler = new WxMaMessageHandler() {
     @Override
-    public void handle(WxMaMessage wxMessage, Map context,
-                       WxMaService service, WxSessionManager sessionManager)
+    public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map context,
+                                    WxMaService service, WxSessionManager sessionManager)
       throws WxErrorException {
       service.getMsgService().sendTemplateMsg(WxMaTemplateMessage.builder()
         .templateId(templateId).data(Lists.newArrayList(
@@ -102,10 +108,22 @@ public void handle(WxMaMessage wxMessage, Map context,
         .toUser(wxMessage.getFromUser())
         .formId("自己替换可用的formid")
         .build());
+      return null;
     }
 
   };
 
+  private static final WxMaMessageHandler customerServiceMessageHandler = new WxMaMessageHandler() {
+    @Override
+    public WxMaXmlOutMessage handle(WxMaMessage message, Map context, WxMaService service, WxSessionManager sessionManager) {
+      return new WxMaXmlOutMessage()
+        .setMsgType(WxConsts.XmlMsgType.TRANSFER_CUSTOMER_SERVICE)
+        .setFromUserName(message.getToUser())
+        .setCreateTime(Calendar.getInstance().getTimeInMillis() / 1000)
+        .setToUserName(message.getFromUser());
+    }
+  };
+
   private static WxMaConfig config;
   private static WxMaService service;
   private static WxMaMessageRouter router;
@@ -142,7 +160,8 @@ private static void init() {
         .rule().async(false).content("模板").handler(templateMsgHandler).end()
         .rule().async(false).content("文本").handler(textHandler).end()
         .rule().async(false).content("图片").handler(picHandler).end()
-        .rule().async(false).content("二维码").handler(qrcodeHandler).end();
+        .rule().async(false).content("二维码").handler(qrcodeHandler).end()
+        .rule().async(false).content("转发客服").handler(customerServiceMessageHandler).end();
     } catch (IOException e) {
       e.printStackTrace();
     }
diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaPortalServlet.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaPortalServlet.java
index 5cadb68925..c209082d45 100644
--- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaPortalServlet.java
+++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaPortalServlet.java
@@ -5,6 +5,8 @@
 import cn.binarywang.wx.miniapp.config.WxMaConfig;
 import cn.binarywang.wx.miniapp.constant.WxMaConstants;
 import cn.binarywang.wx.miniapp.message.WxMaMessageRouter;
+import cn.binarywang.wx.miniapp.message.WxMaXmlOutMessage;
+import lombok.AllArgsConstructor;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.StringUtils;
 
@@ -18,19 +20,13 @@
 /**
  * @author Binary Wang
  */
+@AllArgsConstructor
 public class WxMaPortalServlet extends HttpServlet {
   private static final long serialVersionUID = 1L;
 
-  private WxMaConfig wxMaConfig;
-  private WxMaService wxMaService;
-  private WxMaMessageRouter wxMaMessageRouter;
-
-  WxMaPortalServlet(WxMaConfig wxMaConfig, WxMaService wxMaService,
-                    WxMaMessageRouter wxMaMessageRouter) {
-    this.wxMaConfig = wxMaConfig;
-    this.wxMaService = wxMaService;
-    this.wxMaMessageRouter = wxMaMessageRouter;
-  }
+  private WxMaConfig config;
+  private WxMaService service;
+  private WxMaMessageRouter messageRouter;
 
   @Override
   protected void service(HttpServletRequest request, HttpServletResponse response)
@@ -42,7 +38,7 @@ protected void service(HttpServletRequest request, HttpServletResponse response)
     String nonce = request.getParameter("nonce");
     String timestamp = request.getParameter("timestamp");
 
-    if (!this.wxMaService.checkSignature(timestamp, nonce, signature)) {
+    if (!this.service.checkSignature(timestamp, nonce, signature)) {
       // 消息签名不正确,说明不是公众平台发过来的消息
       response.getWriter().println("非法请求");
       return;
@@ -56,7 +52,7 @@ protected void service(HttpServletRequest request, HttpServletResponse response)
     }
 
     String encryptType = request.getParameter("encrypt_type");
-    final boolean isJson = Objects.equals(this.wxMaConfig.getMsgDataFormat(), WxMaConstants.MsgDataFormat.JSON);
+    final boolean isJson = Objects.equals(this.config.getMsgDataFormat(), WxMaConstants.MsgDataFormat.JSON);
     if (StringUtils.isBlank(encryptType)) {
       // 明文传输的消息
       WxMaMessage inMessage;
@@ -66,7 +62,12 @@ protected void service(HttpServletRequest request, HttpServletResponse response)
         inMessage = WxMaMessage.fromXml(request.getInputStream());
       }
 
-      this.wxMaMessageRouter.route(inMessage);
+      final WxMaXmlOutMessage outMessage = this.messageRouter.route(inMessage);
+      if (outMessage != null) {
+        response.getWriter().write(outMessage.toXml());
+        return;
+      }
+
       response.getWriter().write("success");
       return;
     }
@@ -76,12 +77,16 @@ protected void service(HttpServletRequest request, HttpServletResponse response)
       String msgSignature = request.getParameter("msg_signature");
       WxMaMessage inMessage;
       if (isJson) {
-        inMessage = WxMaMessage.fromEncryptedJson(request.getInputStream(), this.wxMaConfig);
+        inMessage = WxMaMessage.fromEncryptedJson(request.getInputStream(), this.config);
       } else {//xml
-        inMessage = WxMaMessage.fromEncryptedXml(request.getInputStream(), this.wxMaConfig, timestamp, nonce, msgSignature);
+        inMessage = WxMaMessage.fromEncryptedXml(request.getInputStream(), this.config, timestamp, nonce, msgSignature);
       }
 
-      this.wxMaMessageRouter.route(inMessage);
+      final WxMaXmlOutMessage outMessage = this.messageRouter.route(inMessage);
+      if (outMessage != null) {
+        response.getWriter().write(outMessage.toEncryptedXml(this.config));
+        return;
+      }
       response.getWriter().write("success");
       return;
     }

From 7de959f8e58c90545a71cd3c4c1e52892cd09979 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sun, 23 Jun 2019 15:11:19 +0800
Subject: [PATCH 33/74] =?UTF-8?q?=E8=A7=84=E8=8C=83=E9=83=A8=E5=88=86?=
 =?UTF-8?q?=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../wx/miniapp/api/WxMaUserService.java           | 11 +++++++++--
 .../wx/miniapp/api/impl/WxMaUserServiceImpl.java  | 15 +++------------
 2 files changed, 12 insertions(+), 14 deletions(-)

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 a4abdc04d4..3b7abeeb42 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
@@ -13,11 +13,14 @@
  * @author Binary Wang
  */
 public interface WxMaUserService {
+  String SET_USER_STORAGE = "https://api.weixin.qq.com/wxa/set_user_storage?appid=%s&signature=%s&openid=%s&sig_method=%s";
 
   /**
    * 获取登录后的session信息.
    *
    * @param jsCode 登录时获取的 code
+   * @return .
+   * @throws WxErrorException .
    */
   WxMaJscode2SessionResult getSessionInfo(String jsCode) throws WxErrorException;
 
@@ -34,9 +37,11 @@ public interface WxMaUserService {
    * 上报用户数据后台接口.
    * 

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

* 文档参考https://developers.weixin.qq.com/minigame/dev/document/open-api/data/setUserStorage.html - * @param kvMap 要上报的数据 + * + * @param kvMap 要上报的数据 * @param sessionKey 通过wx.login 获得的登录态 - * @param openid + * @param openid . + * @throws WxErrorException . */ void setUserStorage(Map kvMap, String sessionKey, String openid) throws WxErrorException; @@ -46,6 +51,7 @@ public interface WxMaUserService { * @param sessionKey 会话密钥 * @param encryptedData 消息密文 * @param ivStr 加密算法的初始向量 + * @return . */ WxMaPhoneNumberInfo getPhoneNoInfo(String sessionKey, String encryptedData, String ivStr); @@ -55,6 +61,7 @@ public interface WxMaUserService { * @param sessionKey 会话密钥 * @param rawData 微信用户基本信息 * @param signature 数据签名 + * @return . */ boolean checkUserInfo(String sessionKey, String rawData, String signature); } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImpl.java index f8177bf1d6..3c29f85512 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImpl.java @@ -9,28 +9,21 @@ import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils; import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import lombok.AllArgsConstructor; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.SignUtils; -import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.digest.DigestUtils; -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; import java.util.Map; /** * @author Binary Wang */ +@AllArgsConstructor public class WxMaUserServiceImpl implements WxMaUserService { private WxMaService service; - public WxMaUserServiceImpl(WxMaService service) { - this.service = service; - } - @Override public WxMaJscode2SessionResult getSessionInfo(String jsCode) throws WxErrorException { return service.jsCode2SessionInfo(jsCode); @@ -55,9 +48,7 @@ public void setUserStorage(Map kvMap, String sessionKey, String 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 url = String.format(SET_USER_STORAGE, config.getAppid(), signature, openid, "hmac_sha256"); String result = this.service.post(url, params); WxError error = WxError.fromJson(result); if (error.getErrorCode() != 0) { From 0eb3a642c41a314f6dcaf4b3f0af72bf80d28319 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 23 Jun 2019 17:14:07 +0800 Subject: [PATCH 34/74] =?UTF-8?q?=E5=8F=91=E5=B8=833.4.5.B=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- starters/wx-java-mp-starter/pom.xml | 2 +- starters/wx-java-pay-starter/pom.xml | 2 +- weixin-java-common/pom.xml | 2 +- weixin-java-cp/pom.xml | 2 +- weixin-java-miniapp/pom.xml | 2 +- weixin-java-mp/pom.xml | 2 +- weixin-java-open/pom.xml | 2 +- weixin-java-pay/pom.xml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index f6847b14f4..f826bb76e1 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 com.github.binarywang wx-java - 3.4.4.B + 3.4.5.B pom WxJava - Weixin/Wechat Java SDK 微信开发Java SDK diff --git a/starters/wx-java-mp-starter/pom.xml b/starters/wx-java-mp-starter/pom.xml index 6836b174b7..0bb76d4814 100644 --- a/starters/wx-java-mp-starter/pom.xml +++ b/starters/wx-java-mp-starter/pom.xml @@ -6,7 +6,7 @@ com.github.binarywang wx-java - 3.4.4.B + 3.4.5.B ../../ diff --git a/starters/wx-java-pay-starter/pom.xml b/starters/wx-java-pay-starter/pom.xml index a74a48d277..f1a00c5edf 100644 --- a/starters/wx-java-pay-starter/pom.xml +++ b/starters/wx-java-pay-starter/pom.xml @@ -5,7 +5,7 @@ wx-java com.github.binarywang - 3.4.4.B + 3.4.5.B ../../ 4.0.0 diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index 6e589255e4..b2f350b492 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -6,7 +6,7 @@ com.github.binarywang wx-java - 3.4.4.B + 3.4.5.B weixin-java-common diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index d6305ef174..8a831c048a 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.4.4.B + 3.4.5.B weixin-java-cp diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml index c1e270b52d..d6fc851ea8 100644 --- a/weixin-java-miniapp/pom.xml +++ b/weixin-java-miniapp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.4.4.B + 3.4.5.B weixin-java-miniapp diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index 37db924e04..5e678e3bad 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.4.4.B + 3.4.5.B weixin-java-mp diff --git a/weixin-java-open/pom.xml b/weixin-java-open/pom.xml index e1fc0c0839..43a983ea9b 100644 --- a/weixin-java-open/pom.xml +++ b/weixin-java-open/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.4.4.B + 3.4.5.B weixin-java-open diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index e3507fc5a5..de50ca68c8 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -5,7 +5,7 @@ com.github.binarywang wx-java - 3.4.4.B + 3.4.5.B 4.0.0 From 158171c5d1f0711a7e36c92a2b4a51a654df88e2 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 30 Jun 2019 22:21:47 +0800 Subject: [PATCH 35/74] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=B8=80=E7=82=B9?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bean/notify/WxPayNotifyResponse.java | 8 ++++--- .../bean/notify/WxPayNotifyResponseTest.java | 23 +++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayNotifyResponseTest.java 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 c71ed7de67..a7d8f41a22 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 @@ -12,7 +12,9 @@ import me.chanjar.weixin.common.util.xml.XStreamInitializer; /** - * 微信支付订单和退款的异步通知共用的响应类 + * 微信支付订单和退款的异步通知共用的响应类. + * + * @author someone */ @Data @Builder(builderMethodName = "newBuilder") @@ -21,9 +23,9 @@ @XStreamAlias("xml") public class WxPayNotifyResponse { @XStreamOmitField - private transient static final String FAIL = "FAIL"; + private static final transient String FAIL = "FAIL"; @XStreamOmitField - private transient static final String SUCCESS = "SUCCESS"; + private static final transient String SUCCESS = "SUCCESS"; @XStreamAlias("return_code") @XStreamConverter(value = XStreamCDataConverter.class) diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayNotifyResponseTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayNotifyResponseTest.java new file mode 100644 index 0000000000..467854b4bf --- /dev/null +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayNotifyResponseTest.java @@ -0,0 +1,23 @@ +package com.github.binarywang.wxpay.bean.notify; + +import org.testng.annotations.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * WxPayNotifyResponse 测试. + * + * @author Binary Wang + * @date 2019-06-30 + */ +public class WxPayNotifyResponseTest { + + @Test + public void testSuccess() { + final String result = WxPayNotifyResponse.success("OK"); + assertThat(result).isEqualTo("\n" + + " \n" + + " \n" + + ""); + } +} From 7ac670b2873e43070456b059cddff6bdca163e45 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 30 Jun 2019 22:59:58 +0800 Subject: [PATCH 36/74] =?UTF-8?q?#1002=20=E5=A2=9E=E5=8A=A0=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1OCR=E8=BA=AB=E4=BB=BD=E8=AF=81=E8=AF=86=E5=88=AB?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chanjar/weixin/mp/api/WxMpOcrService.java | 50 +++++++++++++++++ .../me/chanjar/weixin/mp/api/WxMpService.java | 9 ++++ .../mp/api/impl/BaseWxMpServiceImpl.java | 11 ++++ .../mp/api/impl/WxMpOcrServiceImpl.java | 43 +++++++++++++++ .../mp/bean/ocr/WxMpOcrIdCardResult.java | 33 ++++++++++++ .../chanjar/weixin/mp/enums/WxMpApiUrl.java | 20 +++++++ .../mp/api/impl/WxMpOcrServiceImplTest.java | 54 +++++++++++++++++++ 7 files changed, 220 insertions(+) create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpOcrService.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpOcrServiceImpl.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/ocr/WxMpOcrIdCardResult.java create mode 100644 weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpOcrServiceImplTest.java diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpOcrService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpOcrService.java new file mode 100644 index 0000000000..1748b55360 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpOcrService.java @@ -0,0 +1,50 @@ +package me.chanjar.weixin.mp.api; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.bean.ocr.WxMpOcrIdCardResult; + +import java.io.File; + +/** + * 基于小程序或 H5 的身份证、银行卡、行驶证 OCR 识别. + * https://mp.weixin.qq.com/wiki?t=resource/res_main&id=21516712284rHWMX + * + * @author Binary Wang + * @date 2019-06-22 + */ +public interface WxMpOcrService { + @AllArgsConstructor + @Getter + enum ImageType { + /** + * 拍照模型,带背景的图片. + */ + PHOTO("photo"), + /** + * 扫描模式,不带背景的图片. + */ + SCAN("scan"); + + private String type; + } + + /** + * 身份证OCR识别接口. + * + * @param imgType 图片类型 + * @param imgUrl 图片url地址 + * @throws WxErrorException . + */ + WxMpOcrIdCardResult idCard(ImageType imgType, String imgUrl) throws WxErrorException; + + /** + * 身份证OCR识别接口. + * + * @param imgType 图片类型 + * @param imgFile 图片文件对象 + * @throws WxErrorException . + */ + WxMpOcrIdCardResult idCard(ImageType imgType, File imgFile) throws WxErrorException; +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java index 35debff565..f9d4399a60 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java @@ -493,6 +493,13 @@ public interface WxMpService { */ WxMpWifiService getWifiService(); + /** + * 返回WIFI接口方法的实现类对象,以方便调用其各个接口. + * + * @return WxMpWifiService + */ + WxMpOcrService getOcrService(); + void setKefuService(WxMpKefuService kefuService); void setMaterialService(WxMpMaterialService materialService); @@ -527,6 +534,8 @@ public interface WxMpService { void setMarketingService(WxMpMarketingService marketingService); + void setOcrService(WxMpOcrService ocrService); + /** * 返回评论数据管理接口方法的实现类对象,以方便调用其各个接口. * diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java index 98220cd9a0..0c7a70cdc7 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java @@ -63,6 +63,7 @@ public abstract class BaseWxMpServiceImpl implements WxMpService, RequestH private WxMpWifiService wifiService = new WxMpWifiServiceImpl(this); private WxMpMarketingService marketingService = new WxMpMarketingServiceImpl(this); private WxMpCommentService commentService = new WxMpCommentServiceImpl(this); + private WxMpOcrService ocrService = new WxMpOcrServiceImpl(this); private Map configStorageMap; @@ -600,6 +601,11 @@ public WxMpWifiService getWifiService() { return this.wifiService; } + @Override + public WxMpOcrService getOcrService() { + return this.ocrService; + } + @Override public WxMpMarketingService getMarketingService() { return this.marketingService; @@ -610,6 +616,11 @@ public void setMarketingService(WxMpMarketingService marketingService) { this.marketingService = marketingService; } + @Override + public void setOcrService(WxMpOcrService ocrService) { + this.ocrService = ocrService; + } + @Override public WxMpCommentService getCommentService() { return this.commentService; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpOcrServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpOcrServiceImpl.java new file mode 100644 index 0000000000..4d3c434ec5 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpOcrServiceImpl.java @@ -0,0 +1,43 @@ +package me.chanjar.weixin.mp.api.impl; + +import lombok.RequiredArgsConstructor; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpOcrService; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.ocr.WxMpOcrIdCardResult; + +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Ocr.IDCARD; + +/** + * ocr 接口实现. + * + * @author Binary Wang + * @date 2019-06-22 + */ +@RequiredArgsConstructor +public class WxMpOcrServiceImpl implements WxMpOcrService { + private final WxMpService wxMpService; + + @Override + public WxMpOcrIdCardResult idCard(ImageType imgType, String imgUrl) throws WxErrorException { + try { + imgUrl = URLEncoder.encode(imgUrl, StandardCharsets.UTF_8.name()); + } catch (UnsupportedEncodingException e) { + // ignore cannot happen + } + + final String result = this.wxMpService.get(String.format(IDCARD.getUrl(this.wxMpService.getWxMpConfigStorage()), + imgType.getType(), imgUrl), null); + return WxMpOcrIdCardResult.fromJson(result); + } + + @Override + public WxMpOcrIdCardResult idCard(ImageType imgType, File imgFile) { + return null; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/ocr/WxMpOcrIdCardResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/ocr/WxMpOcrIdCardResult.java new file mode 100644 index 0000000000..fb1749682b --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/ocr/WxMpOcrIdCardResult.java @@ -0,0 +1,33 @@ +package me.chanjar.weixin.mp.bean.ocr; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +import java.io.Serializable; + +/** + * OCR身份证识别结果. + * + * @author Binary Wang + * @date 2019-06-23 + */ +@Data +public class WxMpOcrIdCardResult implements Serializable { + private static final long serialVersionUID = 8184352486986729980L; + + @SerializedName("type") + private String type; + @SerializedName("name") + private String name; + @SerializedName("id") + private String id; + @SerializedName("valid_date") + private String validDate; + + public static WxMpOcrIdCardResult fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(json, WxMpOcrIdCardResult.class); + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java index 276c1c9e65..e6f529d2ef 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java @@ -426,6 +426,26 @@ public String getUrl(WxMpConfigStorage config) { } } + @AllArgsConstructor + enum Ocr implements WxMpApiUrl { + /** + * 身份证识别. + */ + IDCARD(API_DEFAULT_HOST_URL, "/cv/ocr/idcard?type=%s&img_url=%s"); + + private String prefix; + private String path; + + @Override + public String getUrl(WxMpConfigStorage config) { + if (config == null) { + return buildUrl(null, prefix, path); + } + + return buildUrl(config.getHostConfig(), prefix, path); + } + } + @AllArgsConstructor enum Card implements WxMpApiUrl { /** diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpOcrServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpOcrServiceImplTest.java new file mode 100644 index 0000000000..0170606561 --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpOcrServiceImplTest.java @@ -0,0 +1,54 @@ +package me.chanjar.weixin.mp.api.impl; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpOcrService; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.test.ApiTestModule; +import me.chanjar.weixin.mp.bean.ocr.WxMpOcrIdCardResult; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import javax.inject.Inject; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * 测试类. + * + * @author Binary Wang + * @date 2019-06-22 + */ +@Test +@Guice(modules = ApiTestModule.class) +public class WxMpOcrServiceImplTest { + @Inject + private WxMpService mpService; + + @Test + public void testIdCard() throws WxErrorException { + final WxMpOcrIdCardResult result = this.mpService.getOcrService().idCard(WxMpOcrService.ImageType.PHOTO, + "http://www.baidu.com"); + assertThat(result).isNotNull(); + System.out.println(result); + } + + public static class MockTest { + private WxMpService wxService = mock(WxMpService.class); + + @Test + public void testIdCard() throws Exception { + String returnJson = "{\"type\":\"Back\",\"name\":\"张三\",\"id\":\"110101199909090099\",\"valid_date\":\"20110101-20210201\"}"; + + when(wxService.get(anyString(), anyString())).thenReturn(returnJson); + final WxMpOcrServiceImpl wxMpOcrService = new WxMpOcrServiceImpl(wxService); + + final WxMpOcrIdCardResult result = wxMpOcrService.idCard(WxMpOcrService.ImageType.PHOTO, "abc"); + assertThat(result).isNotNull(); + System.out.println(result); + } + } +} From 37f5e59fbd8f1af211d0807d8bfd57bd1b788fe5 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 30 Jun 2019 23:14:21 +0800 Subject: [PATCH 37/74] =?UTF-8?q?#516=20=E5=AE=9E=E7=8E=B0=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E9=97=A8=E5=BA=97=E7=BD=91=E7=BB=9CWiFi=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/mp/api/WxMpWifiService.java | 18 +++++++++++++++++ .../mp/api/impl/WxMpWifiServiceImpl.java | 20 +++++++++++++++++-- .../chanjar/weixin/mp/enums/WxMpApiUrl.java | 7 ++++++- .../mp/api/impl/WxMpWifiServiceImplTest.java | 7 +++++++ 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpWifiService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpWifiService.java index 1ba40a7714..b0876c7686 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpWifiService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpWifiService.java @@ -45,4 +45,22 @@ public interface WxMpWifiService { * @throws WxErrorException 异常 */ WxMpWifiShopDataResult getShopWifiInfo(int shopId) throws WxErrorException; + + /** + *
+   * 修改门店网络信息.
+   * 通过此接口修改门店的网络信息,包括网络名称(ssid)或密码。需注意:
+   * 只有门店下已添加Wi-Fi网络信息,才能调用此接口修改网络信息;添加方式请参考“添加密码型设备”和"添加portal型设备”接口文档。
+   * 网络信息修改后,密码型设备需同步修改所有设备的ssid或密码;portal型设备需修改所有设备的ssid,并按照《硬件鉴权协议接口》修改“第二步:改造移动端portal页面”中的ssid参数,否则将无法正常连网。
+   * 文档地址:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1457435413
+   * 
+ * + * @param shopId 门店ID + * @param oldSsid 旧的ssid + * @param ssid 无线网络设备的ssid。32个字符以内;ssid支持中文,但可能因设备兼容性问题导致显示乱码,或无法连接等问题,相关风险自行承担! 当门店下是portal型设备时,ssid必填;当门店下是密码型设备时,ssid选填,且ssid和密码必须有一个以大写字母“WX”开头 + * @param password 无线网络设备的密码。8-24个字符;不能包含中文字符; 当门店下是密码型设备时,才可填写password,且ssid和密码必须有一个以大写字母“WX”开头 + * @return 是否更新成功 + * @throws WxErrorException . + */ + boolean updateShopWifiInfo(int shopId, String oldSsid, String ssid, String password) throws WxErrorException; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java index 636ba4fe30..0b75bb996b 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java @@ -8,8 +8,7 @@ import me.chanjar.weixin.mp.bean.wifi.WxMpWifiShopDataResult; import me.chanjar.weixin.mp.bean.wifi.WxMpWifiShopListResult; -import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Wifi.BIZWIFI_SHOP_GET; -import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Wifi.BIZWIFI_SHOP_LIST; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Wifi.*; /** *
@@ -37,4 +36,21 @@ public WxMpWifiShopDataResult getShopWifiInfo(int shopId) throws WxErrorExceptio
     json.addProperty("shop_id", shopId);
     return WxMpWifiShopDataResult.fromJson(this.wxMpService.post(BIZWIFI_SHOP_GET, json.toString()));
   }
+
+  @Override
+  public boolean updateShopWifiInfo(int shopId, String oldSsid, String ssid, String password) throws WxErrorException {
+    JsonObject json = new JsonObject();
+    json.addProperty("shop_id", shopId);
+    json.addProperty("old_ssid", oldSsid);
+    json.addProperty("ssid", ssid);
+    if (password != null) {
+      json.addProperty("password", password);
+    }
+    try {
+      this.wxMpService.post(BIZWIFI_SHOP_UPDATE, json.toString());
+      return true;
+    } catch (WxErrorException e) {
+      throw e;
+    }
+  }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java
index e6f529d2ef..22aeaa0bb5 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java
@@ -391,7 +391,12 @@ enum Wifi implements WxMpApiUrl {
     /**
      * get.
      */
-    BIZWIFI_SHOP_GET(API_DEFAULT_HOST_URL, "/bizwifi/shop/get");
+    BIZWIFI_SHOP_GET(API_DEFAULT_HOST_URL, "/bizwifi/shop/get"),
+
+    /**
+     * upadte.
+     */
+    BIZWIFI_SHOP_UPDATE(API_DEFAULT_HOST_URL, "/bizwifi/shop/update");
 
     private String prefix;
     private String path;
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImplTest.java
index 9ef98f77fe..d9225c7bc5 100644
--- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImplTest.java
+++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImplTest.java
@@ -43,6 +43,13 @@ public void testGetShopWifiInfo() throws WxErrorException {
     System.out.println(wifiInfo);
   }
 
+  @Test
+  public void testUpdateShopWifiInfo() throws WxErrorException {
+    final boolean result = this.wxService.getWifiService()
+      .updateShopWifiInfo(123, "123", "345", null);
+    assertThat(result).isTrue();
+  }
+
   public static class MockTest {
     private WxMpService wxService = mock(WxMpService.class);
 

From 16bb8f122ac5df92e856ab694c669b28f1b8dafb Mon Sep 17 00:00:00 2001
From: winter 
Date: Mon, 8 Jul 2019 16:33:21 +0800
Subject: [PATCH 38/74] =?UTF-8?q?#1100=20=E5=B0=8F=E7=A8=8B=E5=BA=8F?=
 =?UTF-8?q?=E6=A8=A1=E5=9D=97=E6=B7=BB=E5=8A=A0Redis=E9=85=8D=E7=BD=AE?=
 =?UTF-8?q?=E7=B1=BBWxMaInRedisConfig?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pom.xml                                       |   2 +-
 weixin-java-miniapp/pom.xml                   |   6 +
 .../wx/miniapp/config/WxMaInRedisConfig.java  | 404 ++++++++++++++++++
 3 files changed, 411 insertions(+), 1 deletion(-)
 create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaInRedisConfig.java

diff --git a/pom.xml b/pom.xml
index f826bb76e1..6b28296863 100644
--- a/pom.xml
+++ b/pom.xml
@@ -246,7 +246,7 @@
       
         org.projectlombok
         lombok
-        1.16.18
+        1.18.8
         provided
       
     
diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml
index d6fc851ea8..3253a2e13b 100644
--- a/weixin-java-miniapp/pom.xml
+++ b/weixin-java-miniapp/pom.xml
@@ -80,6 +80,12 @@
       org.projectlombok
       lombok
     
+ 	
+	  com.github.jedis-lock
+	  jedis-lock
+	  1.0.0
+	  true
+	
   
 
   
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaInRedisConfig.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaInRedisConfig.java
new file mode 100644
index 0000000000..c90be60a79
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaInRedisConfig.java
@@ -0,0 +1,404 @@
+package cn.binarywang.wx.miniapp.config;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+
+import com.github.jedis.lock.JedisLock;
+
+import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder;
+import me.chanjar.weixin.common.bean.WxAccessToken;
+import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.JedisPool;
+
+/**
+ * 基于Redis的微信配置provider.
+ * 
+ * 
+ * 需要引入依赖jedis-lock,才能使用该类。
+ * 
+ * + * @author winter + */ +public class WxMaInRedisConfig implements WxMaConfig { + + private static final String ACCESS_TOKEN = "accessToken"; + private static final String JSAPI_TICKET = "jsapiTicket"; + private static final String CARD_API_TICKET = "cardApiTicket"; + + private static final String HASH_VALUE_FIELD = "value"; + private static final String HASH_EXPIRE_FIELD = "expire"; + + protected JedisPool jedisPool; + /** + * 微信小程序唯一id,用于拼接存储到redis时的key,防止key重复 + */ + protected String maId; + + protected volatile String msgDataFormat; + protected volatile String appid; + protected volatile String secret; + protected volatile String token; + protected volatile String aesKey; + + protected volatile String httpProxyHost; + protected volatile int httpProxyPort; + protected volatile String httpProxyUsername; + protected volatile String httpProxyPassword; + + protected Lock accessTokenLock; + protected Lock jsapiTicketLock; + protected Lock cardApiTicketLock; + + /** + * 临时文件目录 + */ + protected volatile File tmpDirFile; + + protected volatile ApacheHttpClientBuilder apacheHttpClientBuilder; + + private String getRedisKey(String key) { + StringBuilder redisKey = new StringBuilder("maConfig:"); + if(maId == null) { + return redisKey.append(key).toString(); + } else { + return redisKey.append(maId).append(":").append(key).toString(); + } + } + + private String getValueFromRedis(String key) { + Jedis jedis = jedisPool.getResource(); + try { + return jedis.hget(getRedisKey(key), HASH_VALUE_FIELD); + } finally { + jedis.close(); + } + } + + private void setValueToRedis(String key, long expiresTime, String value) { + Jedis jedis = jedisPool.getResource(); + try { + Map hash = new HashMap(); + hash.put(HASH_VALUE_FIELD, value); + hash.put(HASH_EXPIRE_FIELD, String.valueOf(expiresTime)); + jedis.hmset(getRedisKey(key), hash); + } finally { + jedis.close(); + } + } + + private long getExpireFromRedis(String key) { + Jedis jedis = jedisPool.getResource(); + try { + String expire = jedis.hget(getRedisKey(key), HASH_EXPIRE_FIELD); + return expire == null ? 0 : Long.valueOf(expire); + } finally { + jedis.close(); + } + } + + private void setExpire(String key, long expiresTime) { + Jedis jedis = jedisPool.getResource(); + try { + jedis.hset(getRedisKey(key), HASH_EXPIRE_FIELD, String.valueOf(expiresTime)); + } finally { + jedis.close(); + } + } + + public void setJedisPool(JedisPool jedisPool) { + this.jedisPool = jedisPool; + } + + public void setMaId(String maId) { + this.maId = maId; + } + + @Override + public String getAccessToken() { + return getValueFromRedis(ACCESS_TOKEN); + } + + @Override + public Lock getAccessTokenLock() { + if(accessTokenLock == null) { + synchronized (this) { + if(accessTokenLock == null) { + accessTokenLock = new DistributedLock(getRedisKey("accessTokenLock")); + } + } + } + return accessTokenLock; + } + + @Override + public boolean isAccessTokenExpired() { + return System.currentTimeMillis() > getExpireFromRedis(ACCESS_TOKEN); + } + + @Override + public synchronized void updateAccessToken(WxAccessToken accessToken) { + updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); + } + + @Override + public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { + setValueToRedis(ACCESS_TOKEN, System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L, accessToken); + } + + @Override + public String getJsapiTicket() { + return getValueFromRedis(JSAPI_TICKET); + } + + @Override + public Lock getJsapiTicketLock() { + if(jsapiTicketLock == null) { + synchronized (this) { + if(jsapiTicketLock == null) { + jsapiTicketLock = new DistributedLock(getRedisKey("jsapiTicketLock")); + } + } + } + return jsapiTicketLock; + } + + @Override + public boolean isJsapiTicketExpired() { + return System.currentTimeMillis() > getExpireFromRedis(JSAPI_TICKET); + } + + @Override + public void expireJsapiTicket() { + setExpire(JSAPI_TICKET, 0); + } + + @Override + public void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { + // 预留200秒的时间 + setValueToRedis(JSAPI_TICKET, System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L, jsapiTicket); + } + + + @Override + public String getCardApiTicket() { + return getValueFromRedis(CARD_API_TICKET); + } + + @Override + public Lock getCardApiTicketLock() { + if(cardApiTicketLock == null) { + synchronized (this) { + if(cardApiTicketLock == null) { + cardApiTicketLock = new DistributedLock(getRedisKey("cardApiTicketLock")); + } + } + } + return cardApiTicketLock; + } + + @Override + public boolean isCardApiTicketExpired() { + return System.currentTimeMillis() > getExpireFromRedis(CARD_API_TICKET); + } + + @Override + public void expireCardApiTicket() { + setExpire(CARD_API_TICKET, 0); + } + + @Override + public void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) { + setValueToRedis(CARD_API_TICKET, System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L, cardApiTicket); + } + + @Override + public void expireAccessToken() { + setExpire(ACCESS_TOKEN, 0); + } + + @Override + public String getSecret() { + return this.secret; + } + + public void setSecret(String secret) { + this.secret = secret; + } + + @Override + public String getToken() { + return this.token; + } + + public void setToken(String token) { + this.token = token; + } + + @Override + public long getExpiresTime() { + return getExpireFromRedis(ACCESS_TOKEN); + } + + @Override + public String getAesKey() { + return this.aesKey; + } + + public void setAesKey(String aesKey) { + this.aesKey = aesKey; + } + + @Override + public String getMsgDataFormat() { + return this.msgDataFormat; + } + + public void setMsgDataFormat(String msgDataFormat) { + this.msgDataFormat = msgDataFormat; + } + + @Override + public String getHttpProxyHost() { + return this.httpProxyHost; + } + + public void setHttpProxyHost(String httpProxyHost) { + this.httpProxyHost = httpProxyHost; + } + + @Override + public int getHttpProxyPort() { + return this.httpProxyPort; + } + + public void setHttpProxyPort(int httpProxyPort) { + this.httpProxyPort = httpProxyPort; + } + + @Override + public String getHttpProxyUsername() { + return this.httpProxyUsername; + } + + public void setHttpProxyUsername(String httpProxyUsername) { + this.httpProxyUsername = httpProxyUsername; + } + + @Override + public String getHttpProxyPassword() { + return this.httpProxyPassword; + } + + public void setHttpProxyPassword(String httpProxyPassword) { + this.httpProxyPassword = httpProxyPassword; + } + + @Override + public String toString() { + return WxMaGsonBuilder.create().toJson(this); + } + + @Override + public ApacheHttpClientBuilder getApacheHttpClientBuilder() { + return this.apacheHttpClientBuilder; + } + + public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) { + this.apacheHttpClientBuilder = apacheHttpClientBuilder; + } + + @Override + public boolean autoRefreshToken() { + return true; + } + + @Override + public String getAppid() { + return appid; + } + + public void setAppid(String appid) { + this.appid = appid; + } + + /** + * 基于redis的简单分布式锁 + */ + private class DistributedLock implements Lock { + + private JedisLock lock; + + private DistributedLock(String key) { + this.lock = new JedisLock(getRedisKey(key)); + } + + @Override + public void lock() { + Jedis jedis = jedisPool.getResource(); + try { + if(!lock.acquire(jedis)) { + throw new RuntimeException("acquire timeouted"); + } + } catch (InterruptedException e) { + throw new RuntimeException("lock failed",e); + } finally { + jedis.close(); + } + } + + @Override + public void lockInterruptibly() throws InterruptedException { + Jedis jedis = jedisPool.getResource(); + try { + if(!lock.acquire(jedis)) { + throw new RuntimeException("acquire timeouted"); + } + } finally { + jedis.close(); + } + } + + @Override + public boolean tryLock() { + Jedis jedis = jedisPool.getResource(); + try { + return lock.acquire(jedis); + } catch (InterruptedException e) { + throw new RuntimeException("lock failed",e); + } finally { + jedis.close(); + } + } + + @Override + public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { + Jedis jedis = jedisPool.getResource(); + try { + return lock.acquire(jedis); + } finally { + jedis.close(); + } + } + + @Override + public void unlock() { + Jedis jedis = jedisPool.getResource(); + try { + lock.release(jedis); + } finally { + jedis.close(); + } + } + + @Override + public Condition newCondition() { + throw new RuntimeException("unsupported method"); + } + + } +} From 663c45c77e77f6e48389b1279513db743165cd92 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 8 Jul 2019 17:41:14 +0800 Subject: [PATCH 39/74] =?UTF-8?q?=E5=8F=91=E5=B8=833.4.6.B=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- starters/wx-java-mp-starter/pom.xml | 2 +- starters/wx-java-pay-starter/pom.xml | 2 +- weixin-java-common/pom.xml | 2 +- weixin-java-cp/pom.xml | 2 +- weixin-java-miniapp/pom.xml | 2 +- weixin-java-mp/pom.xml | 2 +- weixin-java-open/pom.xml | 2 +- weixin-java-pay/pom.xml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index 6b28296863..b1f205f010 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 com.github.binarywang wx-java - 3.4.5.B + 3.4.6.B pom WxJava - Weixin/Wechat Java SDK 微信开发Java SDK diff --git a/starters/wx-java-mp-starter/pom.xml b/starters/wx-java-mp-starter/pom.xml index 0bb76d4814..244d264a7b 100644 --- a/starters/wx-java-mp-starter/pom.xml +++ b/starters/wx-java-mp-starter/pom.xml @@ -6,7 +6,7 @@ com.github.binarywang wx-java - 3.4.5.B + 3.4.6.B ../../ diff --git a/starters/wx-java-pay-starter/pom.xml b/starters/wx-java-pay-starter/pom.xml index f1a00c5edf..f26960f16a 100644 --- a/starters/wx-java-pay-starter/pom.xml +++ b/starters/wx-java-pay-starter/pom.xml @@ -5,7 +5,7 @@ wx-java com.github.binarywang - 3.4.5.B + 3.4.6.B ../../ 4.0.0 diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index b2f350b492..23bf2aa18d 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -6,7 +6,7 @@ com.github.binarywang wx-java - 3.4.5.B + 3.4.6.B weixin-java-common diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index 8a831c048a..04f895b292 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.4.5.B + 3.4.6.B weixin-java-cp diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml index 3253a2e13b..1e080244b2 100644 --- a/weixin-java-miniapp/pom.xml +++ b/weixin-java-miniapp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.4.5.B + 3.4.6.B weixin-java-miniapp diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index 5e678e3bad..cd9b92a144 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.4.5.B + 3.4.6.B weixin-java-mp diff --git a/weixin-java-open/pom.xml b/weixin-java-open/pom.xml index 43a983ea9b..f52b6bc79a 100644 --- a/weixin-java-open/pom.xml +++ b/weixin-java-open/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.4.5.B + 3.4.6.B weixin-java-open diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index de50ca68c8..bc2265a31a 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -5,7 +5,7 @@ com.github.binarywang wx-java - 3.4.5.B + 3.4.6.B 4.0.0 From 09b726fd0b62708de88bc4b838afc745b7f0b640 Mon Sep 17 00:00:00 2001 From: ArBing Date: Sun, 14 Jul 2019 14:20:27 +0800 Subject: [PATCH 40/74] =?UTF-8?q?#1106=20=E4=BF=AE=E5=A4=8D=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E5=85=AC=E4=BC=97=E5=8F=B7=20jsapi=5Fticket=20=20?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=20Url=20=E6=8B=BC=E6=8E=A5=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java index 0c7a70cdc7..8b854ebbaf 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java @@ -97,7 +97,7 @@ public String getTicket(TicketType type, boolean forceRefresh) throws WxErrorExc if (this.getWxMpConfigStorage().isTicketExpired(type)) { String responseContent = execute(SimpleGetRequestExecutor.create(this), - GET_TICKET_URL + type.getCode(), null); + GET_TICKET_URL.getUrl(this.getWxMpConfigStorage()) + type.getCode(), null); JsonObject tmpJsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject(); String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); From b3462243e5492e33708539e5e9124cc7136dc5fa Mon Sep 17 00:00:00 2001 From: billytomato Date: Sun, 14 Jul 2019 14:22:17 +0800 Subject: [PATCH 41/74] =?UTF-8?q?#1099=20=E4=BC=98=E5=8C=96=E5=AE=A2?= =?UTF-8?q?=E6=9C=8D=E6=B6=88=E6=81=AF=E6=8E=A5=E5=8F=A3=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/mp/bean/kefu/WxMpKefuMessage.java | 10 ++++- .../mp/builder/kefu/WxMsgMenuBuilder.java | 39 ++++++++++++------- .../util/json/WxMpKefuMessageGsonAdapter.java | 25 ++++++------ .../mp/bean/kefu/WxMpKefuMessageTest.java | 19 ++++++--- 4 files changed, 59 insertions(+), 34 deletions(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessage.java index b2966213b8..ceb62cdfc0 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessage.java @@ -32,10 +32,10 @@ public class WxMpKefuMessage implements Serializable { private String mpNewsMediaId; private String miniProgramAppId; private String miniProgramPagePath; - private List articles = new ArrayList<>(); - private String headContent; private String tailContent; + private List articles = new ArrayList<>(); + private List list = new ArrayList<>(); /** * 菜单消息里的菜单内容. * 请使用逗号分割的形式将id和content连起来放在数组的里面 @@ -145,4 +145,10 @@ public static class WxArticle implements Serializable { private String url; private String picUrl; } + + @Data + public static class WxMsgMenu implements Serializable { + private String id; + private String content; + } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/WxMsgMenuBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/WxMsgMenuBuilder.java index 81d919ecd2..06f6bbd322 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/WxMsgMenuBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/WxMsgMenuBuilder.java @@ -3,30 +3,37 @@ import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + /** - * 卡券消息builder + * 菜单消息builder *
- * 用法: WxMpKefuMessage m = WxMpKefuMessage.WXCARD().cardId(...).toUser(...).build();
+ * 用法:
+ * WxMpKefuMessage m = WxMpKefuMessage.MSGMENU().addList(lists).headContent(headContent).tailContent(tailContent).toUser(...).build();
  * 
* - * @author Binary Wang + * @author billytomato */ public final class WxMsgMenuBuilder extends BaseBuilder { + private List list = new ArrayList<>(); private String headContent; private String tailContent; - private String[] msgMenuList; + public WxMsgMenuBuilder() { this.msgType = WxConsts.KefuMsgType.MSGMENU; } - @Override - public WxMpKefuMessage build() { - WxMpKefuMessage m = super.build(); - m.setHeadContent(this.headContent); - m.setMsgMenuList(this.msgMenuList); - m.setTailContent(this.tailContent); - return m; + public WxMsgMenuBuilder addList(WxMpKefuMessage.WxMsgMenu... list) { + Collections.addAll(this.list, list); + return this; + } + + public WxMsgMenuBuilder list(List list) { + this.list = list; + return this; } public WxMsgMenuBuilder headContent(String headContent) { @@ -39,8 +46,12 @@ public WxMsgMenuBuilder tailContent(String tailContent) { return this; } - public WxMsgMenuBuilder msgMenuList(String... msgMenuList) { - this.msgMenuList = msgMenuList; - return this; + @Override + public WxMpKefuMessage build() { + WxMpKefuMessage m = super.build(); + m.setHeadContent(this.headContent); + m.setTailContent(this.tailContent); + m.setList(this.list); + return m; } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpKefuMessageGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpKefuMessageGsonAdapter.java index 342a4b36a6..57eee1b772 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpKefuMessageGsonAdapter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpKefuMessageGsonAdapter.java @@ -81,19 +81,18 @@ public JsonElement serialize(WxMpKefuMessage message, Type typeOfSrc, JsonSerial messageJson.add("miniprogrampage", miniProgramPage); break; case KefuMsgType.MSGMENU: { - JsonObject msgMenu = new JsonObject(); - JsonArray array = new JsonArray(); - for (String s : message.getMsgMenuList()) { - JsonObject innerJson = new JsonObject(); - final String[] split = s.split(","); - innerJson.addProperty("id", split[0]); - innerJson.addProperty("content", split[1]); - array.add(innerJson); - } - msgMenu.addProperty("head_content", message.getHeadContent()); - msgMenu.add("list", array); - msgMenu.addProperty("tail_content", message.getTailContent()); - messageJson.add("msgmenu", msgMenu); + JsonObject msgmenuJsonObject = new JsonObject(); + JsonArray listJsonArray = new JsonArray(); + for (WxMpKefuMessage.WxMsgMenu list : message.getList()) { + JsonObject listJson = new JsonObject(); + listJson.addProperty("id", list.getId()); + listJson.addProperty("content", list.getContent()); + listJsonArray.add(listJson); + } + msgmenuJsonObject.addProperty("head_content",message.getHeadContent()); + msgmenuJsonObject.add("list", listJsonArray); + msgmenuJsonObject.addProperty("tail_content",message.getTailContent()); + messageJson.add("msgmenu", msgmenuJsonObject); break; } default: { diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessageTest.java index cf45873b51..5e31454335 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessageTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessageTest.java @@ -156,15 +156,24 @@ public void testMiniProgramPageBuild() { } public void testMsgMenuBuild() { + + WxMpKefuMessage.WxMsgMenu wxMsgMenu1=new WxMpKefuMessage.WxMsgMenu(); + wxMsgMenu1.setId("101"); + wxMsgMenu1.setContent("msgmenu1"); + + WxMpKefuMessage.WxMsgMenu wxMsgMenu2=new WxMpKefuMessage.WxMsgMenu(); + wxMsgMenu2.setId("102"); + wxMsgMenu2.setContent("msgmenu2"); + WxMpKefuMessage reply = WxMpKefuMessage.MSGMENU() .toUser("OPENID") - .msgMenuList("101,满意", "102,不满意") - .headContent("您对本次服务是否满意呢?") - .tailContent("欢迎再次光临") + .addList(wxMsgMenu1).addList(wxMsgMenu2) + .headContent("head_content") + .tailContent("tail_content") .build(); - assertThat(reply.toJson()) - .isEqualTo("{\"touser\":\"OPENID\",\"msgtype\":\"msgmenu\",\"msgmenu\":{\"head_content\":\"您对本次服务是否满意呢?\",\"list\":[{\"id\":\"101\",\"content\":\"满意\"},{\"id\":\"102\",\"content\":\"不满意\"}],\"tail_content\":\"欢迎再次光临\"}}"); + Assert.assertEquals(reply.toJson(), + "{\"touser\":\"OPENID\",\"msgtype\":\"msgmenu\",\"msgmenu\":{\"head_content\":\"head_content\",\"list\":[{\"id\":\"101\",\"content\":\"msgmenu1\"},{\"id\":\"102\",\"content\":\"msgmenu2\"}],\"tail_content\":\"tail_content\"}}"); } } From 9149cd441ad4abab49a4a920bb9d2a50f983963b Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 14 Jul 2019 14:24:34 +0800 Subject: [PATCH 42/74] =?UTF-8?q?#1088=20=E5=BE=AE=E4=BF=A1=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E7=BB=93=E6=9E=9C=E9=80=9A=E7=9F=A5=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E7=BB=86=E5=BE=AE=E8=B0=83=E6=95=B4=EF=BC=8C=E5=B8=8C=E6=9C=9B?= =?UTF-8?q?=E8=83=BD=E8=A7=A3=E5=86=B3=E9=83=A8=E5=88=86=E4=BA=BA=E9=81=87?= =?UTF-8?q?=E5=88=B0=E7=9A=84=E5=8F=98=E6=80=81=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../binarywang/wxpay/bean/notify/WxPayNotifyResponse.java | 4 ++-- .../wxpay/bean/notify/WxPayNotifyResponseTest.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) 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 a7d8f41a22..ed1353284f 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 @@ -44,7 +44,7 @@ public static String fail(String msg) { WxPayNotifyResponse response = new WxPayNotifyResponse(FAIL, msg); XStream xstream = XStreamInitializer.getInstance(); xstream.autodetectAnnotations(true); - return xstream.toXML(response); + return xstream.toXML(response).replace("\n", "").replace(" ", ""); } /** @@ -57,7 +57,7 @@ public static String success(String msg) { WxPayNotifyResponse response = new WxPayNotifyResponse(SUCCESS, msg); XStream xstream = XStreamInitializer.getInstance(); xstream.autodetectAnnotations(true); - return xstream.toXML(response); + return xstream.toXML(response).replace("\n", "").replace(" ", ""); } } diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayNotifyResponseTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayNotifyResponseTest.java index 467854b4bf..1baaa8eadd 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayNotifyResponseTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayNotifyResponseTest.java @@ -15,9 +15,9 @@ public class WxPayNotifyResponseTest { @Test public void testSuccess() { final String result = WxPayNotifyResponse.success("OK"); - assertThat(result).isEqualTo("\n" + - " \n" + - " \n" + + assertThat(result).isEqualTo("" + + "" + + "" + ""); } } From 4ae6c435f512e065a2934a1210701e4be428bf0a Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 14 Jul 2019 14:36:31 +0800 Subject: [PATCH 43/74] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=EF=BC=8C=E8=A7=84=E8=8C=83=E5=8F=98=E9=87=8F=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/mp/bean/kefu/WxMpKefuMessage.java | 15 +++++++++++---- .../weixin/mp/builder/kefu/WxMsgMenuBuilder.java | 14 +++++++------- .../mp/util/json/WxMpKefuMessageGsonAdapter.java | 2 +- .../weixin/mp/bean/kefu/WxMpKefuMessageTest.java | 14 ++------------ 4 files changed, 21 insertions(+), 24 deletions(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessage.java index ceb62cdfc0..37beb77e78 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessage.java @@ -1,6 +1,8 @@ package me.chanjar.weixin.mp.bean.kefu; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.mp.builder.kefu.*; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; @@ -35,12 +37,11 @@ public class WxMpKefuMessage implements Serializable { private String headContent; private String tailContent; private List articles = new ArrayList<>(); - private List list = new ArrayList<>(); + /** * 菜单消息里的菜单内容. - * 请使用逗号分割的形式将id和content连起来放在数组的里面 */ - private String[] msgMenuList; + private List msgMenus = new ArrayList<>(); /** * 获得文本消息builder. @@ -137,6 +138,8 @@ public String toJson() { } @Data + @AllArgsConstructor + @NoArgsConstructor public static class WxArticle implements Serializable { private static final long serialVersionUID = 5145137235440507379L; @@ -147,7 +150,11 @@ public static class WxArticle implements Serializable { } @Data - public static class WxMsgMenu implements Serializable { + @AllArgsConstructor + @NoArgsConstructor + public static class MsgMenu implements Serializable { + private static final long serialVersionUID = 7020769047598378839L; + private String id; private String content; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/WxMsgMenuBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/WxMsgMenuBuilder.java index 06f6bbd322..ac3edc236e 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/WxMsgMenuBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/builder/kefu/WxMsgMenuBuilder.java @@ -11,13 +11,13 @@ * 菜单消息builder *
  * 用法:
- * WxMpKefuMessage m = WxMpKefuMessage.MSGMENU().addList(lists).headContent(headContent).tailContent(tailContent).toUser(...).build();
+ * WxMpKefuMessage m = WxMpKefuMessage.MSGMENU().addMenus(lists).headContent(headContent).tailContent(tailContent).toUser(...).build();
  * 
* * @author billytomato */ public final class WxMsgMenuBuilder extends BaseBuilder { - private List list = new ArrayList<>(); + private List msgMenus = new ArrayList<>(); private String headContent; private String tailContent; @@ -26,13 +26,13 @@ public WxMsgMenuBuilder() { this.msgType = WxConsts.KefuMsgType.MSGMENU; } - public WxMsgMenuBuilder addList(WxMpKefuMessage.WxMsgMenu... list) { - Collections.addAll(this.list, list); + public WxMsgMenuBuilder addMenus(WxMpKefuMessage.MsgMenu... msgMenus) { + Collections.addAll(this.msgMenus, msgMenus); return this; } - public WxMsgMenuBuilder list(List list) { - this.list = list; + public WxMsgMenuBuilder msgMenus(List msgMenus) { + this.msgMenus = msgMenus; return this; } @@ -51,7 +51,7 @@ public WxMpKefuMessage build() { WxMpKefuMessage m = super.build(); m.setHeadContent(this.headContent); m.setTailContent(this.tailContent); - m.setList(this.list); + m.setMsgMenus(this.msgMenus); return m; } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpKefuMessageGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpKefuMessageGsonAdapter.java index 57eee1b772..e9e5112d31 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpKefuMessageGsonAdapter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpKefuMessageGsonAdapter.java @@ -83,7 +83,7 @@ public JsonElement serialize(WxMpKefuMessage message, Type typeOfSrc, JsonSerial case KefuMsgType.MSGMENU: { JsonObject msgmenuJsonObject = new JsonObject(); JsonArray listJsonArray = new JsonArray(); - for (WxMpKefuMessage.WxMsgMenu list : message.getList()) { + for (WxMpKefuMessage.MsgMenu list : message.getMsgMenus()) { JsonObject listJson = new JsonObject(); listJson.addProperty("id", list.getId()); listJson.addProperty("content", list.getContent()); diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessageTest.java index 5e31454335..ec754875da 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessageTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/kefu/WxMpKefuMessageTest.java @@ -5,8 +5,6 @@ import org.testng.Assert; import org.testng.annotations.Test; -import static org.assertj.core.api.Assertions.assertThat; - @Test public class WxMpKefuMessageTest { @@ -156,18 +154,10 @@ public void testMiniProgramPageBuild() { } public void testMsgMenuBuild() { - - WxMpKefuMessage.WxMsgMenu wxMsgMenu1=new WxMpKefuMessage.WxMsgMenu(); - wxMsgMenu1.setId("101"); - wxMsgMenu1.setContent("msgmenu1"); - - WxMpKefuMessage.WxMsgMenu wxMsgMenu2=new WxMpKefuMessage.WxMsgMenu(); - wxMsgMenu2.setId("102"); - wxMsgMenu2.setContent("msgmenu2"); - WxMpKefuMessage reply = WxMpKefuMessage.MSGMENU() .toUser("OPENID") - .addList(wxMsgMenu1).addList(wxMsgMenu2) + .addMenus(new WxMpKefuMessage.MsgMenu("101", "msgmenu1"), + new WxMpKefuMessage.MsgMenu("102", "msgmenu2")) .headContent("head_content") .tailContent("tail_content") .build(); From 113407a2139e78f5f2d3049722dfc6c9e1e0a979 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 14 Jul 2019 14:46:06 +0800 Subject: [PATCH 44/74] =?UTF-8?q?#1108=20=E5=BE=AE=E4=BF=A1=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E7=BB=93=E6=9E=9C=E9=80=9A=E7=9F=A5=E7=B1=BB=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=A2=83=E5=A4=96=E5=95=86=E6=88=B7=E4=B8=93=E6=9C=89?= =?UTF-8?q?=E7=9A=84rate=5Fvalue=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bean/notify/WxPayOrderNotifyResult.java | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) 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 433342f9ca..d0242788a1 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,8 +1,5 @@ package com.github.binarywang.wxpay.bean.notify; -import java.util.List; -import java.util.Map; - import com.github.binarywang.wxpay.bean.result.BaseWxPayResult; import com.github.binarywang.wxpay.constant.WxPayConstants; import com.github.binarywang.wxpay.converter.WxPayOrderNotifyResultConverter; @@ -17,8 +14,13 @@ import me.chanjar.weixin.common.util.json.WxGsonBuilder; 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 + * 支付结果通知. + * 文档见:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8 + * https://pay.weixin.qq.com/wiki/doc/api/external/native.php?chapter=9_7 * * @author aimilin6688 * @since 2.5.0 @@ -285,17 +287,29 @@ public class WxPayOrderNotifyResult extends BaseWxPayResult { */ @XStreamAlias("version") private String version; - + + /** + *
+   * 字段名:汇率.
+   * 变量名:rate_value
+   * 类型:String(16)
+   * 示例值:650000000
+   * 标价币种与支付币种的兑换比例乘以10的8次方即为此值,例如美元兑换人民币的比例为6.5,则rate_value=650000000
+   * 
+ */ + @XStreamAlias("rate_value") + private String rateValue; + @Override public void checkResult(WxPayService wxPayService, String signType, boolean checkSuccess) throws WxPayException { //防止伪造成功通知 if (WxPayConstants.ResultCode.SUCCESS.equals(getReturnCode()) && getSign() == null) { throw new WxPayException("伪造的通知!"); } - + super.checkResult(wxPayService, signType, checkSuccess); } - + /** * From xml wx pay order notify result. * From d451d3b779eac9496f1967f2358e89e8d82a7c06 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 14 Jul 2019 14:56:25 +0800 Subject: [PATCH 45/74] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mp/api/impl/WxMpMassMessageServiceImpl.java | 14 ++++++++------ .../chanjar/weixin/mp/bean/WxMpMassTagMessage.java | 12 ++++++------ .../util/json/WxMpMassTagMessageGsonAdapter.java | 4 +++- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMassMessageServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMassMessageServiceImpl.java index 2b23b0ba67..caca3cd057 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMassMessageServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMassMessageServiceImpl.java @@ -11,6 +11,8 @@ import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult; import me.chanjar.weixin.mp.enums.WxMpApiUrl; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.*; + /** *
  * 群发消息服务类
@@ -26,31 +28,31 @@ public class WxMpMassMessageServiceImpl implements WxMpMassMessageService {
 
   @Override
   public WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException {
-    String responseContent = this.wxMpService.post(WxMpApiUrl.MassMessage.MEDIA_UPLOAD_NEWS_URL, news.toJson());
+    String responseContent = this.wxMpService.post(MassMessage.MEDIA_UPLOAD_NEWS_URL, news.toJson());
     return WxMpMassUploadResult.fromJson(responseContent);
   }
 
   @Override
   public WxMpMassUploadResult massVideoUpload(WxMpMassVideo video) throws WxErrorException {
-    String responseContent = this.wxMpService.post(WxMpApiUrl.MassMessage.MEDIA_UPLOAD_VIDEO_URL, video.toJson());
+    String responseContent = this.wxMpService.post(MassMessage.MEDIA_UPLOAD_VIDEO_URL, video.toJson());
     return WxMpMassUploadResult.fromJson(responseContent);
   }
 
   @Override
   public WxMpMassSendResult massGroupMessageSend(WxMpMassTagMessage message) throws WxErrorException {
-    String responseContent = this.wxMpService.post(WxMpApiUrl.MassMessage.MESSAGE_MASS_SENDALL_URL, message.toJson());
+    String responseContent = this.wxMpService.post(MassMessage.MESSAGE_MASS_SENDALL_URL, message.toJson());
     return WxMpMassSendResult.fromJson(responseContent);
   }
 
   @Override
   public WxMpMassSendResult massOpenIdsMessageSend(WxMpMassOpenIdsMessage message) throws WxErrorException {
-    String responseContent = this.wxMpService.post(WxMpApiUrl.MassMessage.MESSAGE_MASS_SEND_URL, message.toJson());
+    String responseContent = this.wxMpService.post(MassMessage.MESSAGE_MASS_SEND_URL, message.toJson());
     return WxMpMassSendResult.fromJson(responseContent);
   }
 
   @Override
   public WxMpMassSendResult massMessagePreview(WxMpMassPreviewMessage wxMpMassPreviewMessage) throws WxErrorException {
-    String responseContent = this.wxMpService.post(WxMpApiUrl.MassMessage.MESSAGE_MASS_PREVIEW_URL, wxMpMassPreviewMessage.toJson());
+    String responseContent = this.wxMpService.post(MassMessage.MESSAGE_MASS_PREVIEW_URL, wxMpMassPreviewMessage.toJson());
     return WxMpMassSendResult.fromJson(responseContent);
   }
 
@@ -59,7 +61,7 @@ public void delete(Long msgId, Integer articleIndex) throws WxErrorException {
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("msg_id", msgId);
     jsonObject.addProperty("article_idx", articleIndex);
-    this.wxMpService.post(WxMpApiUrl.MassMessage.MESSAGE_MASS_DELETE_URL, jsonObject.toString());
+    this.wxMpService.post(MassMessage.MESSAGE_MASS_DELETE_URL, jsonObject.toString());
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassTagMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassTagMessage.java
index 0a72814af8..5e0b638e9f 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassTagMessage.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassTagMessage.java
@@ -7,7 +7,7 @@
 import java.io.Serializable;
 
 /**
- * 按标签群发的消息
+ * 按标签群发的消息.
  *
  * @author chanjarster
  */
@@ -16,12 +16,12 @@ public class WxMpMassTagMessage implements Serializable {
   private static final long serialVersionUID = -6625914040986749286L;
 
   /**
-   * 标签id,如果不设置则就意味着发给所有用户
+   * 标签id,如果不设置则就意味着发给所有用户.
    */
   private Long tagId;
   /**
    * 
-   * 消息类型
+   * 消息类型.
    * 请使用
    * {@link WxConsts.MassMsgType#IMAGE}
    * {@link WxConsts.MassMsgType#MPNEWS}
@@ -35,17 +35,17 @@ public class WxMpMassTagMessage implements Serializable {
   private String content;
   private String mediaId;
   /**
-   * 是否群发给所有用户
+   * 是否群发给所有用户.
    */
   private boolean isSendAll = false;
 
   /**
-   * 文章被判定为转载时,是否继续进行群发操作。
+   * 文章被判定为转载时,是否继续进行群发操作.
    */
   private boolean sendIgnoreReprint = false;
 
   /**
-   * 开发者侧群发msgid,长度限制64字节,如不填,则后台默认以群发范围和群发内容的摘要值做为clientmsgid
+   * 开发者侧群发msgid,长度限制64字节,如不填,则后台默认以群发范围和群发内容的摘要值做为clientmsgid.
    */
   private String clientMsgId;
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassTagMessageGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassTagMessageGsonAdapter.java
index 3d8f58ffa9..b73540d1f1 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassTagMessageGsonAdapter.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpMassTagMessageGsonAdapter.java
@@ -11,7 +11,9 @@
 import java.lang.reflect.Type;
 
 /**
- * @author someone
+ * 群发消息json转换适配器.
+ *
+ * @author chanjarster
  */
 public class WxMpMassTagMessageGsonAdapter implements JsonSerializer {
 

From c805444154029e08a4e94da2d18c014e385c7834 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sun, 14 Jul 2019 15:17:08 +0800
Subject: [PATCH 46/74] =?UTF-8?q?#1095=20=E4=BF=AE=E5=A4=8D=E5=BE=AE?=
 =?UTF-8?q?=E4=BF=A1=E8=90=A5=E9=94=80=E6=8E=A5=E5=8F=A3=E4=B8=AD=E6=9C=89?=
 =?UTF-8?q?=E9=97=AE=E9=A2=98=E7=9A=84=E5=9B=9E=E4=BC=A0=E6=95=B0=E6=8D=AE?=
 =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E6=96=B9=E6=B3=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../weixin/mp/api/WxMpMarketingService.java   | 12 +++----
 .../mp/api/impl/WxMpMarketingServiceImpl.java | 10 ++----
 .../mp/bean/marketing/WxMpUserAction.java     | 34 +++++++++++++++++--
 .../impl/WxMpMarketingServiceImplTest.java    | 30 ++++++++++++++++
 .../mp/bean/marketing/WxMpUserActionTest.java | 28 +++++++++++++++
 5 files changed, 98 insertions(+), 16 deletions(-)
 create mode 100644 weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMarketingServiceImplTest.java
 create mode 100644 weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/marketing/WxMpUserActionTest.java

diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMarketingService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMarketingService.java
index c35a135ce7..d82a9e3287 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMarketingService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMarketingService.java
@@ -11,16 +11,14 @@
 import java.util.List;
 
 /**
- * 
- * 微信营销接口
- * 
+ * 微信营销接口. * * @author 007 */ public interface WxMpMarketingService { /** *
-   * 创建数据源
+   * 创建数据源.
    * 接口调用请求说明
    * https://wximg.qq.com/wxp/pdftool/get.html?id=rkalQXDBM&pa=39
    * 
@@ -33,7 +31,7 @@ public interface WxMpMarketingService { /** *
-   * 获取数据源信息
+   * 获取数据源信息.
    * 
* * @param userActionSetId 数据源唯一ID @@ -41,7 +39,7 @@ public interface WxMpMarketingService { List getUserActionSets(Long userActionSetId) throws WxErrorException; /** - * 回传数据 + * 回传数据. * 接口调用请求说明 * https://wximg.qq.com/wxp/pdftool/get.html?id=rkalQXDBM&pa=39 * @@ -51,7 +49,7 @@ public interface WxMpMarketingService { /** *
-   * 获取朋友圈销售线索数据接口
+   * 获取朋友圈销售线索数据接口.
    * 接口调用请求说明
    *
    * http请求方式: POST
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMarketingServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMarketingServiceImpl.java
index 5f2ece51fe..27371ef8fa 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMarketingServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMarketingServiceImpl.java
@@ -50,15 +50,11 @@ public List getUserActionSets(Long userActionSetId) throws Wx
 
   @Override
   public void addUserAction(List actions) throws WxErrorException {
-    JsonArray json = new JsonArray();
-    for (WxMpUserAction action : actions) {
-      json.add(action.toJsonObject());
-    }
-    wxMpService.post(USER_ACTIONS_ADD, json.toString());
+    wxMpService.post(USER_ACTIONS_ADD, WxMpUserAction.listToJson(actions));
   }
 
   @Override
-  public WxMpAdLeadResult getAdLeads(Date beginDate, Date endDate, List filtering, Integer page, Integer page_size) throws WxErrorException, IOException {
+  public WxMpAdLeadResult getAdLeads(Date beginDate, Date endDate, List filtering, Integer page, Integer pageSize) throws WxErrorException, IOException {
     Date today = new Date();
     if (beginDate == null) {
       beginDate = today;
@@ -72,7 +68,7 @@ public WxMpAdLeadResult getAdLeads(Date beginDate, Date endDate, List007
  */
 
 @Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
 public class WxMpUserAction implements Serializable {
   private static final long serialVersionUID = 7042393762652152209L;
+
   private Long userActionSetId;
   private String url;
-  private Boolean actionTime;
+  private Integer actionTime;
   private String actionType;
   private String clickId;
   private Integer actionParam;
 
-  public JsonObject toJsonObject() {
+  private JsonObject toJsonObject() {
     JsonObject json = new JsonObject();
     json.addProperty("user_action_set_id", this.userActionSetId);
     json.addProperty("url", this.url);
     json.addProperty("action_time", this.actionTime);
+    json.addProperty("action_type", this.actionType);
+
     if (this.clickId != null) {
       JsonObject traceJson = new JsonObject();
       traceJson.addProperty("click_id", this.clickId);
       json.add("trace", traceJson);
     }
+
     if (this.actionParam != null) {
       JsonObject actionParamJson = new JsonObject();
       actionParamJson.addProperty("value", actionParam);
       json.add("action_param", actionParamJson);
     }
+
     return json;
   }
+
+  /**
+   * list对象转换为json字符串
+   *
+   * @param actions .
+   * @return .
+   */
+  public static String listToJson(List actions) {
+    JsonArray array = new JsonArray();
+    for (WxMpUserAction action : actions) {
+      array.add(action.toJsonObject());
+    }
+
+    JsonObject result = new JsonObject();
+    result.add("actions", array);
+    return result.toString();
+  }
 }
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMarketingServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMarketingServiceImplTest.java
new file mode 100644
index 0000000000..900453b669
--- /dev/null
+++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMarketingServiceImplTest.java
@@ -0,0 +1,30 @@
+package me.chanjar.weixin.mp.api.impl;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.*;
+
+/**
+ * 测试类.
+ *
+ * @author Binary Wang
+ * @date 2019-07-14
+ */
+public class WxMpMarketingServiceImplTest {
+
+  @Test
+  public void testAddUserActionSets() {
+  }
+
+  @Test
+  public void testGetUserActionSets() {
+  }
+
+  @Test
+  public void testAddUserAction() {
+  }
+
+  @Test
+  public void testGetAdLeads() {
+  }
+}
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/marketing/WxMpUserActionTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/marketing/WxMpUserActionTest.java
new file mode 100644
index 0000000000..3d18b1ebbc
--- /dev/null
+++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/marketing/WxMpUserActionTest.java
@@ -0,0 +1,28 @@
+package me.chanjar.weixin.mp.bean.marketing;
+
+import com.google.common.collect.Lists;
+import org.testng.annotations.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * 老板加点注释吧.
+ *
+ * @author Binary Wang
+ * @date 2019-07-14
+ */
+public class WxMpUserActionTest {
+
+  @Test
+  public void testListToJson() {
+    assertThat(WxMpUserAction.listToJson(Lists.newArrayList(WxMpUserAction.builder()
+      .actionParam(1)
+      .actionTime(122)
+      .actionType("haha")
+      .clickId("111")
+      .url("1222")
+      .userActionSetId(111L)
+      .build()
+    ))).isEqualTo("{\"actions\":[{\"user_action_set_id\":111,\"url\":\"1222\",\"action_time\":122,\"action_type\":\"haha\",\"trace\":{\"click_id\":\"111\"},\"action_param\":{\"value\":1}}]}");
+  }
+}

From 48742dddccebe412ff76e6ced5341504b76aca4c Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sun, 14 Jul 2019 15:50:00 +0800
Subject: [PATCH 47/74] =?UTF-8?q?=E5=8F=91=E5=B8=833.4.7.B=E6=B5=8B?=
 =?UTF-8?q?=E8=AF=95=E7=89=88=E6=9C=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pom.xml                              | 2 +-
 starters/wx-java-mp-starter/pom.xml  | 2 +-
 starters/wx-java-pay-starter/pom.xml | 2 +-
 weixin-java-common/pom.xml           | 2 +-
 weixin-java-cp/pom.xml               | 2 +-
 weixin-java-miniapp/pom.xml          | 2 +-
 weixin-java-mp/pom.xml               | 2 +-
 weixin-java-open/pom.xml             | 2 +-
 weixin-java-pay/pom.xml              | 2 +-
 9 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/pom.xml b/pom.xml
index b1f205f010..288c9ded4c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
   4.0.0
   com.github.binarywang
   wx-java
-  3.4.6.B
+  3.4.7.B
   pom
   WxJava - Weixin/Wechat Java SDK
   微信开发Java SDK
diff --git a/starters/wx-java-mp-starter/pom.xml b/starters/wx-java-mp-starter/pom.xml
index 244d264a7b..5de791d0f7 100644
--- a/starters/wx-java-mp-starter/pom.xml
+++ b/starters/wx-java-mp-starter/pom.xml
@@ -6,7 +6,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.6.B
+    3.4.7.B
     ../../
   
 
diff --git a/starters/wx-java-pay-starter/pom.xml b/starters/wx-java-pay-starter/pom.xml
index f26960f16a..dee1790d83 100644
--- a/starters/wx-java-pay-starter/pom.xml
+++ b/starters/wx-java-pay-starter/pom.xml
@@ -5,7 +5,7 @@
   
     wx-java
     com.github.binarywang
-    3.4.6.B
+    3.4.7.B
     ../../
   
   4.0.0
diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml
index 23bf2aa18d..f3f6b6c89d 100644
--- a/weixin-java-common/pom.xml
+++ b/weixin-java-common/pom.xml
@@ -6,7 +6,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.6.B
+    3.4.7.B
   
 
   weixin-java-common
diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml
index 04f895b292..9b9d86878e 100644
--- a/weixin-java-cp/pom.xml
+++ b/weixin-java-cp/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.6.B
+    3.4.7.B
   
 
   weixin-java-cp
diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml
index 1e080244b2..d2396f38cf 100644
--- a/weixin-java-miniapp/pom.xml
+++ b/weixin-java-miniapp/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.6.B
+    3.4.7.B
   
 
   weixin-java-miniapp
diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml
index cd9b92a144..a7a5b0feeb 100644
--- a/weixin-java-mp/pom.xml
+++ b/weixin-java-mp/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.6.B
+    3.4.7.B
   
 
   weixin-java-mp
diff --git a/weixin-java-open/pom.xml b/weixin-java-open/pom.xml
index f52b6bc79a..0c2735c008 100644
--- a/weixin-java-open/pom.xml
+++ b/weixin-java-open/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.6.B
+    3.4.7.B
   
 
   weixin-java-open
diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml
index bc2265a31a..59d4dcd7d0 100644
--- a/weixin-java-pay/pom.xml
+++ b/weixin-java-pay/pom.xml
@@ -5,7 +5,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.6.B
+    3.4.7.B
   
   4.0.0
 

From 55ce13865afc7219859cda9145924f790d86d41c Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sun, 14 Jul 2019 17:58:03 +0800
Subject: [PATCH 48/74] =?UTF-8?q?#1110=20=E5=BE=AE=E4=BF=A1=E8=90=A5?=
 =?UTF-8?q?=E9=94=80=E5=9B=9E=E4=BC=A0=E6=95=B0=E6=8D=AE=E6=8E=A5=E5=8F=A3?=
 =?UTF-8?q?=E6=96=B0=E5=A2=9Eleads=5Ftype=E5=8F=82=E6=95=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../me/chanjar/weixin/mp/api/WxMpMarketingService.java    | 8 ++++++--
 .../weixin/mp/api/impl/WxMpMarketingServiceImpl.java      | 5 +++--
 .../chanjar/weixin/mp/bean/marketing/WxMpUserAction.java  | 2 ++
 3 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMarketingService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMarketingService.java
index d82a9e3287..c7daa1f991 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMarketingService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMarketingService.java
@@ -61,7 +61,11 @@ public interface WxMpMarketingService {
    * @param endDate   结束日期
    * @param filtering 过滤条件
    * @param page      页码,获取指定页数据
-   * @param page_size 一页获取的数据条数(1-100)
+   * @param pageSize  一页获取的数据条数(1-100)
+   * @return .
+   * @throws WxErrorException .
+   * @throws IOException      .
    */
-  WxMpAdLeadResult getAdLeads(Date beginDate, Date endDate, List filtering, Integer page, Integer page_size) throws WxErrorException, IOException;
+  WxMpAdLeadResult getAdLeads(Date beginDate, Date endDate, List filtering, Integer page, Integer pageSize)
+    throws WxErrorException, IOException;
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMarketingServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMarketingServiceImpl.java
index 27371ef8fa..6ec51e744f 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMarketingServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMarketingServiceImpl.java
@@ -54,7 +54,8 @@ public void addUserAction(List actions) throws WxErrorException
   }
 
   @Override
-  public WxMpAdLeadResult getAdLeads(Date beginDate, Date endDate, List filtering, Integer page, Integer pageSize) throws WxErrorException, IOException {
+  public WxMpAdLeadResult getAdLeads(Date beginDate, Date endDate, List filtering, Integer page, Integer pageSize)
+    throws WxErrorException, IOException {
     Date today = new Date();
     if (beginDate == null) {
       beginDate = today;
@@ -68,7 +69,7 @@ public WxMpAdLeadResult getAdLeads(Date beginDate, Date endDate, List
Date: Thu, 18 Jul 2019 13:39:04 +0800
Subject: [PATCH 49/74] =?UTF-8?q?=20#1119=20=E5=BC=80=E6=94=BE=E5=B9=B3?=
 =?UTF-8?q?=E5=8F=B0=E6=A8=A1=E5=9D=97getAuthorizerList=E6=96=B9=E6=B3=95?=
 =?UTF-8?q?=E9=87=8C=E8=87=AA=E5=8A=A8=E5=88=B7=E6=96=B0refreshToken?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../open/api/impl/WxOpenComponentServiceImpl.java    | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

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 5b71c78393..03d072cdc3 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
@@ -313,7 +313,17 @@ public WxOpenAuthorizerListResult getAuthorizerList(int begin, int len) throws W
     jsonObject.addProperty("offset", begin);
     jsonObject.addProperty("count", len);
     String responseContent = post(url, jsonObject.toString());
-    return WxOpenGsonBuilder.create().fromJson(responseContent, WxOpenAuthorizerListResult.class);
+    WxOpenAuthorizerListResult ret = WxOpenGsonBuilder.create().fromJson(responseContent, WxOpenAuthorizerListResult.class);
+    if(ret != null && ret.getList() != null){
+      for(Map data : ret.getList()){
+        String authorizerAppid = data.get("authorizer_appid");
+        String refreshToken = data.get("refresh_token");
+        if(authorizerAppid != null && refreshToken != null){
+          this.getWxOpenConfigStorage().setAuthorizerRefreshToken(authorizerAppid, refreshToken);
+        }
+      }
+    }
+    return ret;
   }
 
   @Override

From e5338c5b9b77e44ceee2bffd2992f5031fa65584 Mon Sep 17 00:00:00 2001
From: Patrickcai 
Date: Fri, 19 Jul 2019 12:44:52 +0800
Subject: [PATCH 50/74] =?UTF-8?q?#1125=20=E4=BF=AE=E5=A4=8D=E5=BC=80?=
 =?UTF-8?q?=E6=94=BE=E5=B9=B3=E5=8F=B0=E6=8D=A2=E7=BB=91=E5=B0=8F=E7=A8=8B?=
 =?UTF-8?q?=E5=BA=8F=E7=AE=A1=E7=90=86=E5=91=98=E6=8E=A5=E5=8F=A3=E7=9A=84?=
 =?UTF-8?q?=E9=94=99=E8=AF=AF=E5=9C=B0=E5=9D=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../java/me/chanjar/weixin/open/api/WxOpenFastMaService.java    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenFastMaService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenFastMaService.java
index 64db79b929..c6fd7671bd 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenFastMaService.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenFastMaService.java
@@ -52,7 +52,7 @@ public interface WxOpenFastMaService extends WxMaService {
   /**
    * 7 换绑小程序管理员接口
    */
-  String OPEN_COMPONENT_REBIND_ADMIN = "https://api.weixin.qq.com/cgi- bin/account/componentrebindadmin";
+  String OPEN_COMPONENT_REBIND_ADMIN = "https://api.weixin.qq.com/cgi-bin/account/componentrebindadmin";
 
   /**
    * 8.1 获取账号可以设置的所有类目

From e980b52ef2e670f2fadf78010373d24653231af5 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sun, 21 Jul 2019 16:47:53 +0800
Subject: [PATCH 51/74] =?UTF-8?q?#1122=20=E5=BC=80=E6=94=BE=E5=B9=B3?=
 =?UTF-8?q?=E5=8F=B0=E5=AF=B9=E5=A4=96=E6=9A=B4=E9=9C=B2WxOpenMpServiceImp?=
 =?UTF-8?q?l=E7=B1=BB=EF=BC=8C=E6=96=B9=E4=BE=BF=E5=BC=80=E5=8F=91?=
 =?UTF-8?q?=E8=80=85=E7=81=B5=E6=B4=BB=E8=B0=83=E7=94=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java
index 104215bb9e..a29703df16 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java
@@ -9,7 +9,7 @@
 /**
  * @author 007
  */
-/* package(无需对外暴露) */ class WxOpenMpServiceImpl extends WxMpServiceImpl {
+public class WxOpenMpServiceImpl extends WxMpServiceImpl {
   private WxOpenComponentService wxOpenComponentService;
   private WxMpConfigStorage wxMpConfigStorage;
   private String appId;

From d09d2950fadbe590af1020fd3095708cccff5147 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sun, 21 Jul 2019 17:09:50 +0800
Subject: [PATCH 52/74] =?UTF-8?q?#1112=20=E4=BC=81=E4=B8=9A=E5=BE=AE?=
 =?UTF-8?q?=E4=BF=A1=E6=88=90=E5=91=98=E7=AE=A1=E7=90=86WxCpUser=E7=B1=BB?=
 =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=96=B0=E7=9A=84is=5Fleader=5Fin=5Fdept?=
 =?UTF-8?q?=E5=AD=97=E6=AE=B5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java | 5 +++++
 .../chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java  | 8 ++++++++
 2 files changed, 13 insertions(+)

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 dcf4789eba..8f4e4989cc 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
@@ -31,6 +31,11 @@ public class WxCpUser implements Serializable {
   private Integer status;
   private Integer enable;
   private Integer isLeader;
+  /**
+   * is_leader_in_dept.
+   * 个数必须和department一致,表示在所在的部门内是否为上级。1表示为上级,0表示非上级。在审批等应用里可以用来标识上级审批人
+   */
+  private Integer[] isLeaderInDept;
   private final List extAttrs = new ArrayList<>();
   private Integer hideMobile;
   private String englishName;
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 84ee7c0f2f..ed125c5708 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
@@ -70,6 +70,7 @@ public WxCpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationC
     user.setStatus(GsonHelper.getInteger(o, "status"));
     user.setEnable(GsonHelper.getInteger(o, "enable"));
     user.setIsLeader(GsonHelper.getInteger(o, "isleader"));
+    user.setIsLeaderInDept(GsonHelper.getIntArray(o, "is_leader_in_dept"));
     user.setHideMobile(GsonHelper.getInteger(o, "hide_mobile"));
     user.setEnglishName(GsonHelper.getString(o, "english_name"));
     user.setTelephone(GsonHelper.getString(o, "telephone"));
@@ -197,6 +198,13 @@ public JsonElement serialize(WxCpUser user, Type typeOfSrc, JsonSerializationCon
     if (user.getIsLeader() != null) {
       o.addProperty("isleader", user.getIsLeader());
     }
+    if (user.getIsLeaderInDept() != null && user.getIsLeaderInDept().length > 0) {
+      JsonArray ary = new JsonArray();
+      for (int item : user.getIsLeaderInDept()) {
+        ary.add(item);
+      }
+      o.add("is_leader_in_dept", ary);
+    }
     if (user.getHideMobile() != null) {
       o.addProperty("hide_mobile", user.getHideMobile());
     }

From 7c6ebe66ae58c0a67724ba687b03e8680b2ba278 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sun, 21 Jul 2019 17:22:15 +0800
Subject: [PATCH 53/74] =?UTF-8?q?#1111=20=E5=BE=AE=E4=BF=A1=E6=94=AF?=
 =?UTF-8?q?=E4=BB=98=E9=85=8D=E7=BD=AE=E6=94=AF=E6=8C=81=E6=8E=A5=E5=8F=A3?=
 =?UTF-8?q?=E8=AF=B7=E6=B1=82=E5=9C=B0=E5=9D=80=E7=9A=84=E5=8F=AF=E9=85=8D?=
 =?UTF-8?q?=E7=BD=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../binarywang/wxpay/config/WxPayConfig.java   | 18 ++++++++++++++++++
 .../service/impl/BaseWxPayServiceImpl.java     |  7 +++----
 2 files changed, 21 insertions(+), 4 deletions(-)

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 93b3b700d0..9192a4bafc 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
@@ -18,6 +18,12 @@
  */
 @Data
 public class WxPayConfig {
+  private static final String DEFAULT_PAY_BASE_URL = "https://api.mch.weixin.qq.com";
+
+  /**
+   * 微信支付接口请求地址域名部分.
+   */
+  private String payBaseUrl = DEFAULT_PAY_BASE_URL;
 
   /**
    * http请求连接超时时间.
@@ -96,6 +102,18 @@ public class WxPayConfig {
   private String httpProxyUsername;
   private String httpProxyPassword;
 
+  /**
+   * 返回所设置的微信支付接口请求地址域名.
+   * @return 微信支付接口请求地址域名
+   */
+  public String getPayBaseUrl() {
+    if (StringUtils.isEmpty(this.payBaseUrl)) {
+      return DEFAULT_PAY_BASE_URL;
+    }
+
+    return this.payBaseUrl;
+  }
+
   /**
    * 初始化ssl.
    *
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 24677ba908..01578a23a5 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
@@ -47,7 +47,6 @@
  * @author Binary Wang
  */
 public abstract class BaseWxPayServiceImpl implements WxPayService {
-  private static final String PAY_BASE_URL = "https://api.mch.weixin.qq.com";
   private static final String TOTAL_FUND_COUNT = "资金流水总笔数";
 
   /**
@@ -89,10 +88,10 @@ public void setConfig(WxPayConfig config) {
   @Override
   public String getPayBaseUrl() {
     if (this.getConfig().isUseSandboxEnv()) {
-      return PAY_BASE_URL + "/sandboxnew";
+      return this.getConfig().getPayBaseUrl() + "/sandboxnew";
     }
 
-    return PAY_BASE_URL;
+    return this.getConfig().getPayBaseUrl();
   }
 
   @Override
@@ -101,7 +100,7 @@ public WxPayRefundResult refund(WxPayRefundRequest request) throws WxPayExceptio
 
     String url = this.getPayBaseUrl() + "/secapi/pay/refund";
     if (this.getConfig().isUseSandboxEnv()) {
-      url = PAY_BASE_URL + "/sandboxnew/pay/refund";
+      url = this.getConfig().getPayBaseUrl() + "/sandboxnew/pay/refund";
     }
 
     String responseContent = this.post(url, request.toXML(), true);

From ca780d71c08bd3d986c3f5bb61b789ac4207d72a Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sun, 21 Jul 2019 17:41:51 +0800
Subject: [PATCH 54/74] =?UTF-8?q?=E5=8F=91=E5=B8=833.4.8.B=E6=B5=8B?=
 =?UTF-8?q?=E8=AF=95=E7=89=88=E6=9C=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pom.xml                              | 2 +-
 starters/wx-java-mp-starter/pom.xml  | 2 +-
 starters/wx-java-pay-starter/pom.xml | 2 +-
 weixin-java-common/pom.xml           | 2 +-
 weixin-java-cp/pom.xml               | 2 +-
 weixin-java-miniapp/pom.xml          | 2 +-
 weixin-java-mp/pom.xml               | 2 +-
 weixin-java-open/pom.xml             | 2 +-
 weixin-java-pay/pom.xml              | 2 +-
 9 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/pom.xml b/pom.xml
index 288c9ded4c..280140aad0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
   4.0.0
   com.github.binarywang
   wx-java
-  3.4.7.B
+  3.4.8.B
   pom
   WxJava - Weixin/Wechat Java SDK
   微信开发Java SDK
diff --git a/starters/wx-java-mp-starter/pom.xml b/starters/wx-java-mp-starter/pom.xml
index 5de791d0f7..f88f648781 100644
--- a/starters/wx-java-mp-starter/pom.xml
+++ b/starters/wx-java-mp-starter/pom.xml
@@ -6,7 +6,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.7.B
+    3.4.8.B
     ../../
   
 
diff --git a/starters/wx-java-pay-starter/pom.xml b/starters/wx-java-pay-starter/pom.xml
index dee1790d83..6c6098308c 100644
--- a/starters/wx-java-pay-starter/pom.xml
+++ b/starters/wx-java-pay-starter/pom.xml
@@ -5,7 +5,7 @@
   
     wx-java
     com.github.binarywang
-    3.4.7.B
+    3.4.8.B
     ../../
   
   4.0.0
diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml
index f3f6b6c89d..38af48bae0 100644
--- a/weixin-java-common/pom.xml
+++ b/weixin-java-common/pom.xml
@@ -6,7 +6,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.7.B
+    3.4.8.B
   
 
   weixin-java-common
diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml
index 9b9d86878e..23ea6f8c65 100644
--- a/weixin-java-cp/pom.xml
+++ b/weixin-java-cp/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.7.B
+    3.4.8.B
   
 
   weixin-java-cp
diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml
index d2396f38cf..8947e01cd1 100644
--- a/weixin-java-miniapp/pom.xml
+++ b/weixin-java-miniapp/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.7.B
+    3.4.8.B
   
 
   weixin-java-miniapp
diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml
index a7a5b0feeb..c875087725 100644
--- a/weixin-java-mp/pom.xml
+++ b/weixin-java-mp/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.7.B
+    3.4.8.B
   
 
   weixin-java-mp
diff --git a/weixin-java-open/pom.xml b/weixin-java-open/pom.xml
index 0c2735c008..8aa08d7064 100644
--- a/weixin-java-open/pom.xml
+++ b/weixin-java-open/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.7.B
+    3.4.8.B
   
 
   weixin-java-open
diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml
index 59d4dcd7d0..4780cb4e18 100644
--- a/weixin-java-pay/pom.xml
+++ b/weixin-java-pay/pom.xml
@@ -5,7 +5,7 @@
   
     com.github.binarywang
     wx-java
-    3.4.7.B
+    3.4.8.B
   
   4.0.0
 

From 364aa0594fb225ab795c0e79cf4dbeacef68438b Mon Sep 17 00:00:00 2001
From: lbwcdg <875560580@qq.com>
Date: Mon, 22 Jul 2019 22:31:34 +0800
Subject: [PATCH 55/74] =?UTF-8?q?#1127=20=E4=BF=AE=E5=A4=8D=E5=BE=AE?=
 =?UTF-8?q?=E4=BF=A1=E7=BA=A2=E5=8C=85=E6=9F=A5=E8=AF=A2=E7=AD=BE=E5=90=8D?=
 =?UTF-8?q?=E9=94=99=E8=AF=AF=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

少过滤 sign_type 参数
---
 .../binarywang/wxpay/bean/request/WxPayRedpackQueryRequest.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRedpackQueryRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRedpackQueryRequest.java
index e8ade81d9f..9303810753 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRedpackQueryRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayRedpackQueryRequest.java
@@ -27,7 +27,7 @@ public class WxPayRedpackQueryRequest extends BaseWxPayRequest {
 
   @Override
   protected String[] getIgnoredParamsForSign() {
-    return new String[]{"sub_appid","sub_mch_id"};
+    return new String[]{"sub_appid","sub_mch_id","sign_type"};
   }
   /**
    * 商户订单号

From 0196764079f14963a24f042d5a54398b62d24f4e Mon Sep 17 00:00:00 2001
From: ArBing 
Date: Wed, 24 Jul 2019 10:12:11 +0800
Subject: [PATCH 56/74] =?UTF-8?q?#1129=20=E6=96=B0=E5=A2=9E=E5=B0=8F?=
 =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E6=8F=92=E4=BB=B6=E7=AE=A1=E7=90=86=E7=9B=B8?=
 =?UTF-8?q?=E5=85=B3=E6=8E=A5=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../wx/miniapp/api/WxMaPluginService.java     | 50 ++++++++++++++++
 .../wx/miniapp/api/WxMaService.java           |  7 +++
 .../api/impl/WxMaPluginServiceImpl.java       | 57 +++++++++++++++++++
 .../wx/miniapp/api/impl/WxMaServiceImpl.java  |  8 ++-
 .../wx/miniapp/bean/WxMaPluginListResult.java | 36 ++++++++++++
 .../api/impl/WxMaPluginServiceImplTest.java   | 39 +++++++++++++
 6 files changed, 196 insertions(+), 1 deletion(-)
 create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaPluginService.java
 create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaPluginServiceImpl.java
 create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaPluginListResult.java
 create mode 100644 weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaPluginServiceImplTest.java

diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaPluginService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaPluginService.java
new file mode 100644
index 0000000000..83e2b1c5aa
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaPluginService.java
@@ -0,0 +1,50 @@
+package cn.binarywang.wx.miniapp.api;
+
+import cn.binarywang.wx.miniapp.bean.WxMaPluginListResult;
+import me.chanjar.weixin.common.error.WxErrorException;
+
+/**
+ * 小程序插件管理 API
+ * 

+ * 详情请见:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/plugin-management/pluginManager.applyPlugin.html + * 或者:https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/Plug-ins_Management.html + */ +public interface WxMaPluginService { + + String PLUGIN_URL = "https://api.weixin.qq.com/wxa/plugin"; + + /** + * 向插件开发者发起使用插件的申请 + * + * @param pluginAppId 插件 appId + * @param reason 申请使用理由 + * @throws WxErrorException 异常 + */ + void applyPlugin(String pluginAppId, String reason) throws WxErrorException; + + /** + * 查询已添加的插件 + * + * @return + * @throws WxErrorException + */ + WxMaPluginListResult getPluginList() throws WxErrorException; + + /** + * 删除已添加的插件 + * + * @param pluginAppId 插件 appId + * @throws WxErrorException + */ + void unbindPlugin(String pluginAppId) throws WxErrorException; + + /** + * 快速更新插件版本号(第三方平台代小程序管理插件) + * + * @param pluginAppId 插件 appid + * @param userVersion 升级至版本号,要求此插件版本支持快速更新 + * @throws WxErrorException + */ + void updatePlugin(String pluginAppId, String userVersion) 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 578acc56af..52988f36e2 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 @@ -207,6 +207,13 @@ public interface WxMaService { */ WxMaSecCheckService getSecCheckService(); + /** + * 返回插件相关接口服务对象. + * + * @return WxMaPluginService + */ + WxMaPluginService getPluginService(); + /** * 初始化http请求对象. */ diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaPluginServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaPluginServiceImpl.java new file mode 100644 index 0000000000..052a0caa6f --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaPluginServiceImpl.java @@ -0,0 +1,57 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaPluginService; +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaPluginListResult; +import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; +import me.chanjar.weixin.common.error.WxErrorException; + +import java.util.HashMap; +import java.util.Map; + +public class WxMaPluginServiceImpl implements WxMaPluginService { + + private WxMaService wxMaService; + + public WxMaPluginServiceImpl(WxMaService wxMaService) { + this.wxMaService = wxMaService; + } + + @Override + public void applyPlugin(String pluginAppId, String reason) throws WxErrorException { + Map params = new HashMap<>(); + params.put("action", "apply"); + params.put("plugin_appid", pluginAppId); + params.put("reason", reason); + + this.wxMaService.post(PLUGIN_URL, WxMaGsonBuilder.create().toJson(params)); + } + + @Override + public WxMaPluginListResult getPluginList() throws WxErrorException { + Map params = new HashMap<>(); + params.put("action", "list"); + + String responseContent = this.wxMaService.post(PLUGIN_URL, WxMaGsonBuilder.create().toJson(params)); + return WxMaPluginListResult.fromJson(responseContent); + } + + @Override + public void unbindPlugin(String pluginAppId) throws WxErrorException { + Map params = new HashMap<>(); + params.put("action", "unbind"); + params.put("plugin_appid", pluginAppId); + + this.wxMaService.post(PLUGIN_URL, WxMaGsonBuilder.create().toJson(params)); + } + + @Override + public void updatePlugin(String pluginAppId, String userVersion) throws WxErrorException { + Map params = new HashMap<>(); + params.put("action", "update"); + params.put("plugin_appid", pluginAppId); + params.put("user_version", userVersion); + + this.wxMaService.post(PLUGIN_URL, WxMaGsonBuilder.create().toJson(params)); + } +} 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 d4f9721805..797dc6b999 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 @@ -53,6 +53,7 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp pluginList; + + public static WxMaPluginListResult fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMaPluginListResult.class); + } + + @Data + public static class PluginInfo { + + @SerializedName("appid") + private String appId; + + private String status; + + @SerializedName("nickname") + private String nickName; + + @SerializedName("headimgurl") + private String headImgUrl; + } +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaPluginServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaPluginServiceImplTest.java new file mode 100644 index 0000000000..ef5882e8f5 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaPluginServiceImplTest.java @@ -0,0 +1,39 @@ +package cn.binarywang.wx.miniapp.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaPluginListResult; +import cn.binarywang.wx.miniapp.test.ApiTestModule; +import com.google.inject.Inject; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertNotNull; + +@Test +@Guice(modules = ApiTestModule.class) +public class WxMaPluginServiceImplTest { + @Inject + private WxMaService wxService; + + @Test + public void testApplyPlugin() throws Exception { + this.wxService.getPluginService().applyPlugin("wx4418e3e031e551be", null); + } + + @Test + public void testGetPluginList() throws Exception { + WxMaPluginListResult result = this.wxService.getPluginService().getPluginList(); + assertNotNull(result); + System.out.println(result.toString()); + } + + @Test + public void testUnbindPlugin() throws Exception { + this.wxService.getPluginService().unbindPlugin("wx4418e3e031e551be"); + } + + @Test + public void testUpdatePlugin() throws Exception { + this.wxService.getPluginService().updatePlugin("wx4418e3e031e551be", "2.0.2"); + } +} From 1793c2576ab87c93f160a46b3c33e316dddcbc4a Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Fri, 26 Jul 2019 23:43:58 +0800 Subject: [PATCH 57/74] =?UTF-8?q?#1126=20=E4=BF=AE=E5=A4=8D=E4=BC=81?= =?UTF-8?q?=E4=B8=9A=E5=BE=AE=E4=BF=A1WxCpXmlMessage=E7=B1=BB=E9=83=A8?= =?UTF-8?q?=E5=88=86=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chanjar/weixin/cp/bean/WxCpXmlMessage.java | 18 ++++++++++++------ .../weixin/cp/bean/WxCpXmlMessageTest.java | 4 ++-- 2 files changed, 14 insertions(+), 8 deletions(-) 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 c201af5cb6..771e57294d 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 @@ -180,17 +180,17 @@ public class WxCpXmlMessage implements Serializable { */ @XStreamAlias("ExternalUserID") @XStreamConverter(value = XStreamCDataConverter.class) - private String externalUserID; + private String externalUserId; /** - * 添加此用户的「联系我」方式配置的state参数,可用于识别添加此用户的渠道 + * 添加此用户的「联系我」方式配置的state参数,可用于识别添加此用户的渠道. */ @XStreamAlias("State") @XStreamConverter(value = XStreamCDataConverter.class) private String state; /** - * 欢迎语code,可用于发送欢迎语 + * 欢迎语code,可用于发送欢迎语. */ @XStreamAlias("WelcomeCode") @XStreamConverter(value = XStreamCDataConverter.class) @@ -211,11 +211,11 @@ public class WxCpXmlMessage implements Serializable { private String name; /** - * 成员部门列表. + * 成员部门列表,变更时推送,仅返回该应用有查看权限的部门id. */ @XStreamAlias("Department") @XStreamConverter(value = XStreamCDataConverter.class) - private String department; + private Long[] departments; /** * 手机号码. @@ -264,6 +264,12 @@ public class WxCpXmlMessage implements Serializable { @XStreamAlias("IsLeader") private Integer isLeader; + /** + * 表示所在部门是否为上级,0-否,1-是,顺序与Department字段的部门逐一对应. + */ + @XStreamAlias("IsLeaderInDept") + private Integer[] isLeaderInDept; + /** * 座机. */ @@ -288,7 +294,7 @@ public class WxCpXmlMessage implements Serializable { * 部门Id. */ @XStreamAlias("Id") - private Integer id; + private Long id; /** * 父部门id. diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java index ad9a04b610..e6efa04382 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java @@ -195,7 +195,7 @@ public void testAddExternalUserEvent() { assertEquals(wxMessage.getMsgType(), WxConsts.XmlMsgType.EVENT); assertEquals(wxMessage.getEvent(), WxCpConsts.EventType.CHANGE_EXTERNAL_CONTACT); assertEquals(wxMessage.getChangeType(), WxCpConsts.ExternalContactChangeType.ADD_EXTERNAL_CONTACT); - assertEquals(wxMessage.getExternalUserID(), "woAJ2GCAAAXtWyujaWJHDDGi0mACH71w"); + assertEquals(wxMessage.getExternalUserId(), "woAJ2GCAAAXtWyujaWJHDDGi0mACH71w"); assertEquals(wxMessage.getState(), "teststate"); assertEquals(wxMessage.getWelcomeCode(), "WELCOMECODE"); @@ -220,6 +220,6 @@ public void testDelExternalUserEvent() { assertEquals(wxMessage.getEvent(), WxCpConsts.EventType.CHANGE_EXTERNAL_CONTACT); assertEquals(wxMessage.getChangeType(), WxCpConsts.ExternalContactChangeType.DEL_EXTERNAL_CONTACT); assertEquals(wxMessage.getUserId(), "zhangsan"); - assertEquals(wxMessage.getExternalUserID(), "woAJ2GCAAAXtWyujaWJHDDGi0mACH71w"); + assertEquals(wxMessage.getExternalUserId(), "woAJ2GCAAAXtWyujaWJHDDGi0mACH71w"); } } From c680a75c9fece23b167b822d6ea013251b4c2844 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 28 Jul 2019 22:39:26 +0800 Subject: [PATCH 58/74] =?UTF-8?q?=E5=8F=91=E5=B8=833.4.9.B=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- starters/wx-java-mp-starter/pom.xml | 2 +- starters/wx-java-pay-starter/pom.xml | 2 +- weixin-java-common/pom.xml | 2 +- weixin-java-cp/pom.xml | 2 +- weixin-java-miniapp/pom.xml | 2 +- weixin-java-mp/pom.xml | 2 +- weixin-java-open/pom.xml | 2 +- weixin-java-pay/pom.xml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index 280140aad0..c7f7187097 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 com.github.binarywang wx-java - 3.4.8.B + 3.4.9.B pom WxJava - Weixin/Wechat Java SDK 微信开发Java SDK diff --git a/starters/wx-java-mp-starter/pom.xml b/starters/wx-java-mp-starter/pom.xml index f88f648781..0350280dea 100644 --- a/starters/wx-java-mp-starter/pom.xml +++ b/starters/wx-java-mp-starter/pom.xml @@ -6,7 +6,7 @@ com.github.binarywang wx-java - 3.4.8.B + 3.4.9.B ../../ diff --git a/starters/wx-java-pay-starter/pom.xml b/starters/wx-java-pay-starter/pom.xml index 6c6098308c..0ce75995ba 100644 --- a/starters/wx-java-pay-starter/pom.xml +++ b/starters/wx-java-pay-starter/pom.xml @@ -5,7 +5,7 @@ wx-java com.github.binarywang - 3.4.8.B + 3.4.9.B ../../ 4.0.0 diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index 38af48bae0..b3461b93ee 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -6,7 +6,7 @@ com.github.binarywang wx-java - 3.4.8.B + 3.4.9.B weixin-java-common diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index 23ea6f8c65..62638cf3f7 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.4.8.B + 3.4.9.B weixin-java-cp diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml index 8947e01cd1..d46ec3e9e2 100644 --- a/weixin-java-miniapp/pom.xml +++ b/weixin-java-miniapp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.4.8.B + 3.4.9.B weixin-java-miniapp diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index c875087725..763e8fea05 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.4.8.B + 3.4.9.B weixin-java-mp diff --git a/weixin-java-open/pom.xml b/weixin-java-open/pom.xml index 8aa08d7064..a0a3067eee 100644 --- a/weixin-java-open/pom.xml +++ b/weixin-java-open/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.4.8.B + 3.4.9.B weixin-java-open diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index 4780cb4e18..00b97de20d 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -5,7 +5,7 @@ com.github.binarywang wx-java - 3.4.8.B + 3.4.9.B 4.0.0 From 7a389ad851ed67420611871c63a1b2477cdc661c Mon Sep 17 00:00:00 2001 From: m8cool <278621965@qq.com> Date: Mon, 29 Jul 2019 11:06:40 +0800 Subject: [PATCH 59/74] =?UTF-8?q?#1125=20=E5=BE=AE=E4=BF=A1=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E6=A8=A1=E5=9D=97=E4=BF=AE=E5=A4=8D=E5=AF=B9=E8=B4=A6?= =?UTF-8?q?=E5=8D=95=E4=B8=8B=E8=BD=BD=E6=8E=A5=E5=8F=A3=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E4=B8=AD=E7=BC=BA=E5=A4=B1=E8=AE=A2=E5=8D=95=E6=80=BB=E9=87=91?= =?UTF-8?q?=E9=A2=9D=E5=92=8C=E7=94=B3=E8=AF=B7=E9=80=80=E6=AC=BE=E6=80=BB?= =?UTF-8?q?=E9=87=91=E9=A2=9D=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wxpay/bean/result/WxPayBillResult.java | 25 ++++++-- .../bean/result/WxPayBillResultTest.java | 64 +++++++++++++++++++ 2 files changed, 82 insertions(+), 7 deletions(-) create mode 100644 weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayBillResultTest.java 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 e568a77d14..15416b1f2a 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,13 +1,13 @@ package com.github.binarywang.wxpay.bean.result; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - import lombok.Data; import lombok.NoArgsConstructor; import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + /** * 微信对账单结果类. * @@ -106,6 +106,7 @@ private static WxPayBillResult fromRawBillResultString(String responseContent) { int j = tempStr.length / t.length; // 纪录数组下标 int k = 1; + // 交易时间,公众账号ID,商户号,特约商户号,设备号,微信订单号,商户订单号,用户标识,交易类型,交易状态,付款银行,货币种类,应结订单金额,代金券金额,微信退款单号,商户退款单号,退款金额,充值券退款金额,退款类型,退款状态,商品名称,商户数据包,手续费,费率,订单金额,申请退款金额,费率备注 for (int i = 0; i < j; i++) { WxPayBillInfo result = new WxPayBillInfo(); result.setTradeTime(tempStr[k].trim()); @@ -132,6 +133,9 @@ private static WxPayBillResult fromRawBillResultString(String responseContent) { result.setAttach(tempStr[k + 21].trim()); result.setPoundage(tempStr[k + 22].trim()); result.setPoundageRate(tempStr[k + 23].trim()); + result.setTotalAmount(tempStr[k + 24].trim()); + result.setAppliedRefundAmount(tempStr[k + 25].trim()); + result.setFeeRemark(tempStr[k + 26].trim()); results.add(result); k += t.length; } @@ -140,7 +144,7 @@ private static WxPayBillResult fromRawBillResultString(String responseContent) { billResult.setBillInfoList(results); /* - * 总交易单数,应结订单总金额,退款总金额,充值券退款总金额,手续费总金额,订单总金额,申请退款总金额 `2,`0.02,`0.0,`0.0,`0 + * 总交易单数,应结订单总金额,退款总金额,充值券退款总金额,手续费总金额,订单总金额,申请退款总金额 `48,`5.76,`1.42,`0.00,`0.01000,`5.76,`1.42 * 参考以上格式进行取值 */ String[] totalTempStr = objStr.replaceAll(",", " ").split("`"); @@ -149,6 +153,9 @@ private static WxPayBillResult fromRawBillResultString(String responseContent) { billResult.setTotalRefundFee(totalTempStr[3].trim()); billResult.setTotalCouponFee(totalTempStr[4].trim()); billResult.setTotalPoundageFee(totalTempStr[5].trim()); + billResult.setTotalAmount(get(totalTempStr, 6)); + billResult.setTotalAppliedRefundFee(get(totalTempStr, 7)); + return billResult; } @@ -174,7 +181,7 @@ private static WxPayBillResult fromRawBillResultStringToSuccess(String responseC int j = tempStr.length / t.length; // 纪录数组下标 int k = 1; - // 交易时间,公众账号ID,商户号,子商户号,设备号,微信订单号,商户订单号,用户标识,交易类型,交易状态,付款银行,货币种类,总金额,代金券或立减优惠金额,商品名称,商户数据包,手续费,费率 + // 交易时间,公众账号ID,商户号,特约商户号,设备号,微信订单号,商户订单号,用户标识,交易类型,交易状态,付款银行,货币种类,应结订单金额,代金券金额,商品名称,商户数据包,手续费,费率,订单金额,费率备注 for (int i = 0; i < j; i++) { WxPayBillInfo result = new WxPayBillInfo(); result.setTradeTime(tempStr[k].trim()); @@ -195,6 +202,8 @@ private static WxPayBillResult fromRawBillResultStringToSuccess(String responseC result.setAttach(tempStr[k + 15].trim()); result.setPoundage(tempStr[k + 16].trim()); result.setPoundageRate(tempStr[k + 17].trim()); + result.setTotalAmount(tempStr[k + 18].trim()); + result.setFeeRemark(tempStr[k + 19].trim()); results.add(result); k += t.length; } @@ -203,7 +212,7 @@ private static WxPayBillResult fromRawBillResultStringToSuccess(String responseC billResult.setBillInfoList(results); /* - * 总交易单数,应结订单总金额,退款总金额,充值券退款总金额,手续费总金额,订单总金额,申请退款总金额 `2,`0.02,`0.0,`0.0,`0 + * 总交易单数,应结订单总金额,退款总金额,充值券退款总金额,手续费总金额,订单总金额,申请退款总金额 `31,`3.05,`0.00,`0.00,`0.02000,`3.05,`0.00 * 参考以上格式进行取值 */ String[] totalTempStr = objStr.replaceAll(",", " ").split("`"); @@ -212,6 +221,8 @@ private static WxPayBillResult fromRawBillResultStringToSuccess(String responseC billResult.setTotalRefundFee(totalTempStr[3].trim()); billResult.setTotalCouponFee(totalTempStr[4].trim()); billResult.setTotalPoundageFee(totalTempStr[5].trim()); + billResult.setTotalAmount(get(totalTempStr, 6)); + billResult.setTotalAppliedRefundFee(get(totalTempStr, 7)); return billResult; } diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayBillResultTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayBillResultTest.java new file mode 100644 index 0000000000..76bbf05742 --- /dev/null +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayBillResultTest.java @@ -0,0 +1,64 @@ +package com.github.binarywang.wxpay.bean.result; + +import com.github.binarywang.wxpay.constant.WxPayConstants; +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * @author m8cool + */ +public class WxPayBillResultTest { + + public static final String PAY_BILL_RESULT_ALL_CONTENT = "交易时间,公众账号ID,商户号,特约商户号,设备号,微信订单号,商户订单号,用户标识,交易类型,交易状态,付款银行,货币种类,应结订单金额,代金券金额,微信退款单号,商户退款单号,退款金额,充值券退款金额,退款类型,退款状态,商品名称,商户数据包,手续费,费率,订单金额,申请退款金额,费率备注\n" + + "`2019-07-25 08:35:41,`WWWW,`XXXXXXXX,`0,`,`XXXXXXXXXXXXX,`XXXXXXXXXX,`XXXXXXXXXXX,`JSAPI,`SUCCESS,`PSBC_DEBIT,`CNY,`6.00,`0.00,`0,`0,`0.00,`0.00,`,`,`XXXXXX,`XXXXXXX,`0.04000,`0.60%,`6.00,`0.00,`\n" + + "总交易单数,应结订单总金额,退款总金额,充值券退款总金额,手续费总金额,订单总金额,申请退款总金额\n" + + "`48,`5.76,`1.42,`0.00,`0.01000,`5.76,`1.42\n"; + public static final String PAY_BILL_RESULT_SUCCESS_CONTENT = "交易时间,公众账号ID,商户号,特约商户号,设备号,微信订单号,商户订单号,用户标识,交易类型,交易状态,付款银行,货币种类,应结订单金额,代金券金额,商品名称,商户数据包,手续费,费率,订单金额,费率备注\n" + + "`2019-07-23 18:46:41,`XXXX,`XXX,`XXX,`,`XXX,`XXX,`XXX,`JSAPI,`SUCCESS,`CFT,`CNY,`0.01,`0.00,`XXX,`XXXX,`0.00000,`0.60%,`0.01,`\n" + + "总交易单数,应结订单总金额,退款总金额,充值券退款总金额,手续费总金额,订单总金额,申请退款总金额\n" + + "`31,`3.05,`0.00,`0.00,`0.02000,`3.05,`0.00"; + public static final String PAY_BILL_RESULT_REFUND_CONTENT = "交易时间,公众账号ID,商户号,特约商户号,设备号,微信订单号,商户订单号,用户标识,交易类型,交易状态,付款银行,货币种类,应结订单金额,代金券金额,退款申请时间,退款成功时间,微信退款单号,商户退款单号,退款金额,充值券退款金额,退款类型,退款状态,商品名称,商户数据包,手续费,费率,订单金额,申请退款金额,费率备注\n" + + "`2019-07-23 20:53:36,`xxx,`xxx,`xxx,`,`xxx,`xxxx,`xxxxx,`JSAPI,`REFUND,`CFT,`CNY,`0.00,`0.00,`2019-07-23 20:53:36,`2019-07-23 20:53:40,`xxxx,`xxx,`0.01,`0.00,`ORIGINAL,`SUCCESS,`xxxx,`xxxx,`0.00000,`0.60%,`0.00,`0.01,`\n" + + "总交易单数,应结订单总金额,退款总金额,充值券退款总金额,手续费总金额,订单总金额,申请退款总金额\n" + + "`4,`0.00,`2.02,`0.00,`-0.02000,`0.00,`2.02"; + + /** + * 测试微信返回类型为ALL时,解析结果是否正确 + */ + @Test + public void testFromRawBillResultStringAll() { + WxPayBillResult result = WxPayBillResult.fromRawBillResultString(PAY_BILL_RESULT_ALL_CONTENT, WxPayConstants.BillType.ALL); + + Assert.assertEquals(result.getTotalRecord(), "48"); + Assert.assertEquals(result.getTotalFee(), "5.76"); + Assert.assertEquals(result.getTotalRefundFee(), "1.42"); + Assert.assertEquals(result.getTotalCouponFee(), "0.00"); + Assert.assertEquals(result.getTotalPoundageFee(), "0.01000"); + Assert.assertEquals(result.getTotalAmount(), "5.76"); + Assert.assertEquals(result.getTotalAppliedRefundFee(), "1.42"); + Assert.assertEquals(result.getBillInfoList().get(0).getTotalAmount(), "6.00"); + Assert.assertEquals(result.getBillInfoList().get(0).getAppliedRefundAmount(), "0.00"); + Assert.assertEquals(result.getBillInfoList().get(0).getFeeRemark(), ""); + + + } + + /** + * 测试微信返回类型为SUCCESS时,解析结果是否正确 + */ + @Test + public void testFromRawBillResultStringSuccess() { + WxPayBillResult result = WxPayBillResult.fromRawBillResultString(PAY_BILL_RESULT_SUCCESS_CONTENT, WxPayConstants.BillType.SUCCESS); + + Assert.assertEquals(result.getTotalRecord(), "31"); + Assert.assertEquals(result.getTotalFee(), "3.05"); + Assert.assertEquals(result.getTotalRefundFee(), "0.00"); + Assert.assertEquals(result.getTotalCouponFee(), "0.00"); + Assert.assertEquals(result.getTotalPoundageFee(), "0.02000"); + Assert.assertEquals(result.getTotalAmount(), "3.05"); + Assert.assertEquals(result.getTotalAppliedRefundFee(), "0.00"); + Assert.assertEquals(result.getBillInfoList().get(0).getTotalAmount(), "0.01"); + Assert.assertEquals(result.getBillInfoList().get(0).getFeeRemark(), ""); + + } +} From a5ccd0adcb2505aad591a50f9830976519806a55 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 3 Aug 2019 23:01:18 +0800 Subject: [PATCH 60/74] =?UTF-8?q?=E5=8E=BB=E6=8E=89=E9=9D=9E=E6=B3=95?= =?UTF-8?q?=E5=AD=97=E7=AC=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java index bf29a55b35..5ce85e7fff 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderRequest.java @@ -311,7 +311,7 @@ public class WxPayUnifiedOrderRequest extends BaseWxPayRequest { * 是否必填:否 * 类型:String(8) * 示例值:Y - * 描述: Y,传入Y时,支付成功消息和支付详情页将出现开票入口。需要在微信支付商户平台或微信公众平台开通电子发票功能,传此字段才可生效 + * 描述:Y,传入Y时,支付成功消息和支付详情页将出现开票入口。需要在微信支付商户平台或微信公众平台开通电子发票功能,传此字段才可生效 *

*/ @XStreamAlias("receipt") From d0d83a7b81389c24bafe737c66dd04d053d10668 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 3 Aug 2019 23:05:41 +0800 Subject: [PATCH 61/74] =?UTF-8?q?#1138=20=E8=8E=B7=E5=8F=96=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E8=8F=9C=E5=8D=95=E9=85=8D=E7=BD=AE=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E7=BB=93=E6=9E=9C=E4=B8=AD=E5=A2=9E=E5=8A=A0=E5=B0=8F?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E7=9B=B8=E5=85=B3=E7=9A=84=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/mp/bean/menu/WxMpSelfMenuInfo.java | 51 +++++++++++++------ 1 file changed, 36 insertions(+), 15 deletions(-) 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 4789b47089..f0e0a1049a 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 @@ -43,13 +43,13 @@ public static class WxMpSelfMenuButton implements Serializable { @SerializedName("type") private String type; /** - * 菜单名称 + * 菜单名称. */ @SerializedName("name") private String name; /** *
-     * 对于不同的菜单类型,value的值意义不同。
+     * 对于不同的菜单类型,value的值意义不同.
      * 官网上设置的自定义菜单:
      *  
  • Text:保存文字到value; *
  • Img、voice:保存mediaID到value; @@ -58,29 +58,52 @@ public static class WxMpSelfMenuButton implements Serializable { *
  • View:保存链接到url。
  • * * 使用API设置的自定义菜单: - *
  • click、scancode_push、scancode_waitmsg、pic_sysphoto、pic_photo_or_album、 pic_weixin、location_select:保存值到key; + *
  • click、scancode_push、scancode_waitmsg、pic_sysphoto、pic_photo_or_album、pic_weixin、location_select:保存值到key; *
  • view:保存链接到url *
  • */ @SerializedName("key") private String key; /** + * . + * * @see #key */ @SerializedName("url") private String url; + /** + * . + * * @see #key */ @SerializedName("value") private String value; + + /** + *
    +     * 小程序的appid.
    +     * miniprogram类型必须
    +     * 
    + */ + @SerializedName("appid") + private String appId; + /** - * 子菜单信息 + *
    +     * 小程序的页面路径.
    +     * miniprogram类型必须
    +     * 
    + */ + @SerializedName("pagepath") + private String pagePath; + /** + * 子菜单信息. */ @SerializedName("sub_button") private SubButtons subButtons; /** - * 图文消息的信息 + * 图文消息的信息. */ @SerializedName("news_info") private NewsInfo newsInfo; @@ -116,42 +139,41 @@ public String toString() { } @Data - public static class NewsInButton implements Serializable { + public static class NewsInButton implements Serializable { private static final long serialVersionUID = 8701455967664912972L; /** - * 图文消息的标题 + * 图文消息的标题. */ @SerializedName("title") private String title; /** - * 摘要 + * 摘要. */ @SerializedName("digest") private String digest; /** - * 作者 + * 作者. */ @SerializedName("author") private String author; /** - * show_cover - * 是否显示封面,0为不显示,1为显示 + * 是否显示封面,0为不显示,1为显示. */ @SerializedName("show_cover") private Integer showCover; /** - * 封面图片的URL + * 封面图片的URL. */ @SerializedName("cover_url") private String coverUrl; /** - * 正文的URL + * 正文的URL. */ @SerializedName("content_url") private String contentUrl; /** - * 原文的URL,若置空则无查看原文入口 + * 原文的URL,若置空则无查看原文入口. */ @SerializedName("source_url") private String sourceUrl; @@ -160,7 +182,6 @@ public static class NewsInButton implements Serializable { public String toString() { return WxMpGsonBuilder.create().toJson(this); } - } } } From d9b72170092a185f3c8cc64fe44ac539b7e29702 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 3 Aug 2019 23:36:44 +0800 Subject: [PATCH 62/74] =?UTF-8?q?=E8=A7=84=E8=8C=83=E7=BB=9F=E4=B8=80confi?= =?UTF-8?q?g=E9=83=A8=E5=88=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mp/WxMpServiceAutoConfiguration.java | 2 +- .../mp/WxMpStorageAutoConfiguration.java | 16 +- .../weixin/cp/config/WxCpTpConfigStorage.java | 12 +- .../WxCpDefaultConfigImpl.java} | 42 +-- .../WxCpRedisConfigImpl.java} | 15 +- .../WxCpTpDefaultConfigImpl.java} | 59 ++-- .../chanjar/weixin/cp/api/ApiTestModule.java | 4 +- .../demo/WxCpDemoInMemoryConfigStorage.java | 4 +- .../WxMaDefaultConfigImpl.java} | 44 +-- .../WxMaRedisConfigImpl.java} | 307 ++++++++---------- .../wx/miniapp/test/TestConfig.java | 4 +- .../me/chanjar/weixin/mp/api/WxMpService.java | 1 + .../mp/api/impl/BaseWxMpServiceImpl.java | 1 + .../api/impl/WxMpServiceHttpClientImpl.java | 2 +- .../mp/api/impl/WxMpServiceJoddHttpImpl.java | 2 +- .../mp/api/impl/WxMpServiceOkHttpImpl.java | 2 +- .../api/impl/WxMpSubscribeMsgServiceImpl.java | 2 +- .../mp/bean/message/WxMpXmlMessage.java | 6 +- .../mp/bean/message/WxMpXmlOutMessage.java | 4 +- .../mp/{api => config}/WxMpConfigStorage.java | 2 +- .../impl/WxMpDefaultConfigImpl.java} | 5 +- .../impl/WxMpRedisConfigImpl.java} | 8 +- .../chanjar/weixin/mp/enums/WxMpApiUrl.java | 2 +- .../weixin/mp/util/crypto/WxMpCryptUtil.java | 2 +- .../mp/api/impl/WxMpServiceImplTest.java | 2 +- .../weixin/mp/api/test/ApiTestModule.java | 2 +- .../weixin/mp/api/test/TestConfigStorage.java | 4 +- .../demo/WxMpDemoInMemoryConfigStorage.java | 4 +- .../weixin/mp/demo/WxMpDemoServer.java | 2 +- .../weixin/mp/demo/WxMpEndpointServlet.java | 2 +- .../weixin/open/api/WxOpenConfigStorage.java | 2 +- .../api/impl/WxOpenInMemoryConfigStorage.java | 2 +- .../open/api/impl/WxOpenMpServiceImpl.java | 2 +- .../WxOpenServiceApacheHttpClientImpl.java | 1 - 34 files changed, 277 insertions(+), 294 deletions(-) rename weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/{WxCpInMemoryConfigStorage.java => impl/WxCpDefaultConfigImpl.java} (85%) rename weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/{WxCpJedisConfigStorage.java => impl/WxCpRedisConfigImpl.java} (93%) rename weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/{WxCpTpInMemoryConfigStorage.java => impl/WxCpTpDefaultConfigImpl.java} (82%) rename weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/{WxMaInMemoryConfig.java => impl/WxMaDefaultConfigImpl.java} (84%) rename weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/{WxMaInRedisConfig.java => impl/WxMaRedisConfigImpl.java} (54%) rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/{api => config}/WxMpConfigStorage.java (98%) rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/{api/WxMpInMemoryConfigStorage.java => config/impl/WxMpDefaultConfigImpl.java} (96%) rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/{api/WxMpInRedisConfigStorage.java => config/impl/WxMpRedisConfigImpl.java} (92%) diff --git a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/WxMpServiceAutoConfiguration.java b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/WxMpServiceAutoConfiguration.java index 7a6cf920c4..a5234ed769 100644 --- a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/WxMpServiceAutoConfiguration.java +++ b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/WxMpServiceAutoConfiguration.java @@ -1,6 +1,6 @@ package com.binarywang.spring.starter.wxjava.mp; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; import org.springframework.beans.factory.annotation.Autowired; diff --git a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/WxMpStorageAutoConfiguration.java b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/WxMpStorageAutoConfiguration.java index a0fb7eb3d5..d70d88c878 100644 --- a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/WxMpStorageAutoConfiguration.java +++ b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/WxMpStorageAutoConfiguration.java @@ -1,8 +1,8 @@ package com.binarywang.spring.starter.wxjava.mp; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; -import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage; -import me.chanjar.weixin.mp.api.WxMpInRedisConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl; +import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; @@ -34,23 +34,23 @@ public WxMpConfigStorage wxMpInMemoryConfigStorage() { return getWxMpInMemoryConfigStorage(); } - private WxMpInMemoryConfigStorage getWxMpInMemoryConfigStorage() { - WxMpInMemoryConfigStorage config = new WxMpInMemoryConfigStorage(); + private WxMpDefaultConfigImpl getWxMpInMemoryConfigStorage() { + WxMpDefaultConfigImpl config = new WxMpDefaultConfigImpl(); setWxMpInfo(config); return config; } - private WxMpInRedisConfigStorage getWxMpInRedisConfigStorage() { + private WxMpRedisConfigImpl getWxMpInRedisConfigStorage() { JedisPool poolToUse = jedisPool; if (poolToUse == null) { poolToUse = getJedisPool(); } - WxMpInRedisConfigStorage config = new WxMpInRedisConfigStorage(poolToUse); + WxMpRedisConfigImpl config = new WxMpRedisConfigImpl(poolToUse); setWxMpInfo(config); return config; } - private void setWxMpInfo(WxMpInMemoryConfigStorage config) { + private void setWxMpInfo(WxMpDefaultConfigImpl config) { config.setAppId(properties.getAppId()); config.setSecret(properties.getSecret()); config.setToken(properties.getToken()); diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java index 44ef4e17be..fadfb0bda6 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java @@ -14,7 +14,6 @@ public interface WxCpTpConfigStorage { /** * 设置企业微信服务器 baseUrl. - * * 默认值是 https://qyapi.weixin.qq.com , 如果使用默认值,则不需要调用 setBaseApiUrl * * @param baseUrl 企业微信服务器 Url @@ -23,7 +22,6 @@ public interface WxCpTpConfigStorage { /** * 读取企业微信 API Url. - * * 支持私有化企业微信服务器. */ String getApiUrl(String path); @@ -33,7 +31,7 @@ public interface WxCpTpConfigStorage { boolean isSuiteAccessTokenExpired(); /** - * 强制将suite access token过期掉 + * 强制将suite access token过期掉. */ void expireSuiteAccessToken(); @@ -46,15 +44,15 @@ public interface WxCpTpConfigStorage { boolean isSuiteTicketExpired(); /** - * 强制将suite ticket过期掉 + * 强制将suite ticket过期掉. */ void expireSuiteTicket(); /** - * 应该是线程安全的 + * 应该是线程安全的. */ void updateSuiteTicket(String suiteTicket, int expiresInSeconds); - + String getCorpId(); String getCorpSecret(); @@ -80,7 +78,7 @@ public interface WxCpTpConfigStorage { File getTmpDirFile(); /** - * http client builder + * http client builder. * * @return ApacheHttpClientBuilder */ 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/impl/WxCpDefaultConfigImpl.java similarity index 85% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpInMemoryConfigStorage.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpDefaultConfigImpl.java index 2ce5750710..87ed4f611c 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/impl/WxCpDefaultConfigImpl.java @@ -1,45 +1,49 @@ -package me.chanjar.weixin.cp.config; +package me.chanjar.weixin.cp.config.impl; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; import me.chanjar.weixin.cp.constant.WxCpApiPathConsts; import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; import java.io.File; +import java.io.Serializable; /** - * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 + * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化. * * @author Daniel Qian */ -public class WxCpInMemoryConfigStorage implements WxCpConfigStorage { - protected volatile String corpId; - protected volatile String corpSecret; +public class WxCpDefaultConfigImpl implements WxCpConfigStorage, Serializable { + private static final long serialVersionUID = 1154541446729462780L; - protected volatile String token; + private volatile String corpId; + private volatile String corpSecret; + + private volatile String token; protected volatile String accessToken; - protected volatile String aesKey; + private volatile String aesKey; protected volatile Integer agentId; - protected volatile long expiresTime; + private volatile long expiresTime; - protected volatile String oauth2redirectUri; + private volatile String oauth2redirectUri; - protected volatile String httpProxyHost; - protected volatile int httpProxyPort; - protected volatile String httpProxyUsername; - protected volatile String httpProxyPassword; + private volatile String httpProxyHost; + private volatile int httpProxyPort; + private volatile String httpProxyUsername; + private volatile String httpProxyPassword; - protected volatile String jsapiTicket; - protected volatile long jsapiTicketExpiresTime; + private volatile String jsapiTicket; + private volatile long jsapiTicketExpiresTime; - protected volatile String agentJsapiTicket; - protected volatile long agentJsapiTicketExpiresTime; + private volatile String agentJsapiTicket; + private volatile long agentJsapiTicketExpiresTime; - protected volatile File tmpDirFile; + private volatile File tmpDirFile; private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; - protected volatile String baseApiUrl; + private volatile String baseApiUrl; @Override public void setBaseApiUrl(String baseUrl) { 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/impl/WxCpRedisConfigImpl.java similarity index 93% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpJedisConfigStorage.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpRedisConfigImpl.java index 652f5fe0c6..ecaa47cc23 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/impl/WxCpRedisConfigImpl.java @@ -1,7 +1,8 @@ -package me.chanjar.weixin.cp.config; +package me.chanjar.weixin.cp.config.impl; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; import me.chanjar.weixin.cp.constant.WxCpApiPathConsts; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; @@ -17,7 +18,7 @@ * * @author gaigeshen */ -public class WxCpJedisConfigStorage implements WxCpConfigStorage { +public class WxCpRedisConfigImpl implements WxCpConfigStorage { private static final String ACCESS_TOKEN_KEY = "WX_CP_ACCESS_TOKEN"; private static final String ACCESS_TOKEN_EXPIRES_TIME_KEY = "WX_CP_ACCESS_TOKEN_EXPIRES_TIME"; private static final String JS_API_TICKET_KEY = "WX_CP_JS_API_TICKET"; @@ -54,23 +55,23 @@ public String getApiUrl(String path) { return baseApiUrl + path; } - public WxCpJedisConfigStorage(JedisPool jedisPool) { + public WxCpRedisConfigImpl(JedisPool jedisPool) { this.jedisPool = jedisPool; } - public WxCpJedisConfigStorage(String host, int port) { + public WxCpRedisConfigImpl(String host, int port) { jedisPool = new JedisPool(host, port); } - public WxCpJedisConfigStorage(JedisPoolConfig poolConfig, String host, int port) { + public WxCpRedisConfigImpl(JedisPoolConfig poolConfig, String host, int port) { jedisPool = new JedisPool(poolConfig, host, port); } - public WxCpJedisConfigStorage(JedisPoolConfig poolConfig, String host, int port, int timeout, String password) { + public WxCpRedisConfigImpl(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, String password, int database) { + public WxCpRedisConfigImpl(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/config/WxCpTpInMemoryConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpDefaultConfigImpl.java similarity index 82% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpInMemoryConfigStorage.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpDefaultConfigImpl.java index 6da47f5b72..d8be83c2af 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpInMemoryConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpDefaultConfigImpl.java @@ -1,44 +1,47 @@ -package me.chanjar.weixin.cp.config; +package me.chanjar.weixin.cp.config.impl; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.cp.config.WxCpTpConfigStorage; import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; import java.io.File; +import java.io.Serializable; /** - * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 + * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化. * - * @author Daniel Qian + * @author someone */ -public class WxCpTpInMemoryConfigStorage implements WxCpTpConfigStorage { - protected volatile String corpId; - protected volatile String corpSecret; - - protected volatile String suiteId; - protected volatile String suiteSecret; +public class WxCpTpDefaultConfigImpl implements WxCpTpConfigStorage, Serializable { + private static final long serialVersionUID = 6678780920621872824L; - protected volatile String token; - protected volatile String suiteAccessToken; - protected volatile String aesKey; - protected volatile long expiresTime; + private volatile String corpId; + private volatile String corpSecret; - protected volatile String oauth2redirectUri; + private volatile String suiteId; + private volatile String suiteSecret; - protected volatile String httpProxyHost; - protected volatile int httpProxyPort; - protected volatile String httpProxyUsername; - protected volatile String httpProxyPassword; + private volatile String token; + private volatile String suiteAccessToken; + private volatile String aesKey; + private volatile long expiresTime; - protected volatile String suiteTicket; - protected volatile long suiteTicketExpiresTime; + private volatile String oauth2redirectUri; + private volatile String httpProxyHost; + private volatile int httpProxyPort; + private volatile String httpProxyUsername; + private volatile String httpProxyPassword; - protected volatile File tmpDirFile; + private volatile String suiteTicket; + private volatile long suiteTicketExpiresTime; + + private volatile File tmpDirFile; private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; - protected volatile String baseApiUrl; + private volatile String baseApiUrl; @Override public void setBaseApiUrl(String baseUrl) { @@ -57,7 +60,7 @@ public String getApiUrl(String path) { public String getSuiteAccessToken() { return this.suiteAccessToken; } - + public void setSuiteAccessToken(String suiteAccessToken) { this.suiteAccessToken = suiteAccessToken; } @@ -82,25 +85,25 @@ public synchronized void updateSuiteAccessToken(String suiteAccessToken, int exp this.suiteAccessToken = suiteAccessToken; this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; } - + @Override public String getCorpId() { return this.corpId; } - + public void setCorpId(String corpId) { this.corpId = corpId; } - + @Override public String getCorpSecret() { return this.corpSecret; } - + public void setCorpSecret(String corpSecret) { this.corpSecret = corpSecret; } - + @Override public String getSuiteTicket() { return this.suiteTicket; diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java index 5ef750f89a..c15e3af4d1 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java @@ -12,7 +12,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias; import me.chanjar.weixin.common.util.xml.XStreamInitializer; import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; -import me.chanjar.weixin.cp.config.WxCpInMemoryConfigStorage; +import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl; public class ApiTestModule implements Module { private final Logger log = LoggerFactory.getLogger(this.getClass()); @@ -44,7 +44,7 @@ public void configure(Binder binder) { } @XStreamAlias("xml") - public static class WxXmlCpInMemoryConfigStorage extends WxCpInMemoryConfigStorage { + public static class WxXmlCpInMemoryConfigStorage extends WxCpDefaultConfigImpl { protected String userId; diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoInMemoryConfigStorage.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoInMemoryConfigStorage.java index cbb3503760..35a2fc0e43 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoInMemoryConfigStorage.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoInMemoryConfigStorage.java @@ -6,14 +6,14 @@ import com.thoughtworks.xstream.annotations.XStreamAlias; import lombok.ToString; import me.chanjar.weixin.common.util.xml.XStreamInitializer; -import me.chanjar.weixin.cp.config.WxCpInMemoryConfigStorage; +import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl; /** * @author Daniel Qian */ @XStreamAlias("xml") @ToString -public class WxCpDemoInMemoryConfigStorage extends WxCpInMemoryConfigStorage { +public class WxCpDemoInMemoryConfigStorage extends WxCpDefaultConfigImpl { public static WxCpDemoInMemoryConfigStorage fromXml(InputStream is) { XStream xstream = XStreamInitializer.getInstance(); xstream.processAnnotations(WxCpDemoInMemoryConfigStorage.class); 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/impl/WxMaDefaultConfigImpl.java similarity index 84% rename from weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaInMemoryConfig.java rename to weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaDefaultConfigImpl.java index a0e53262bb..76ff7611b4 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/impl/WxMaDefaultConfigImpl.java @@ -1,9 +1,10 @@ -package cn.binarywang.wx.miniapp.config; +package cn.binarywang.wx.miniapp.config.impl; import java.io.File; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import cn.binarywang.wx.miniapp.config.WxMaConfig; import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; @@ -13,38 +14,39 @@ * * @author Binary Wang */ -public class WxMaInMemoryConfig implements WxMaConfig { - protected volatile String msgDataFormat; +public class WxMaDefaultConfigImpl implements WxMaConfig { + private volatile String msgDataFormat; protected volatile String appid; - protected volatile String secret; + private volatile String secret; protected volatile String token; - protected volatile String accessToken; - protected volatile String aesKey; - protected volatile long expiresTime; + private volatile String accessToken; + private volatile String aesKey; + private volatile long expiresTime; - protected volatile String httpProxyHost; - protected volatile int httpProxyPort; - protected volatile String httpProxyUsername; - protected volatile String httpProxyPassword; + private volatile String httpProxyHost; + private volatile int httpProxyPort; + private volatile String httpProxyUsername; + private volatile String httpProxyPassword; - protected volatile String jsapiTicket; - protected volatile long jsapiTicketExpiresTime; - - //微信卡券的ticket单独缓存 - protected volatile String cardApiTicket; - protected volatile long cardApiTicketExpiresTime; + private volatile String jsapiTicket; + private volatile long jsapiTicketExpiresTime; + /** + * 微信卡券的ticket单独缓存. + */ + private volatile String cardApiTicket; + private volatile long cardApiTicketExpiresTime; protected Lock accessTokenLock = new ReentrantLock(); - protected Lock jsapiTicketLock = new ReentrantLock(); - protected Lock cardApiTicketLock = new ReentrantLock(); + private Lock jsapiTicketLock = new ReentrantLock(); + private Lock cardApiTicketLock = new ReentrantLock(); /** - * 临时文件目录 + * 临时文件目录. */ protected volatile File tmpDirFile; - protected volatile ApacheHttpClientBuilder apacheHttpClientBuilder; + private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; @Override public String getAccessToken() { diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaInRedisConfig.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaRedisConfigImpl.java similarity index 54% rename from weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaInRedisConfig.java rename to weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaRedisConfigImpl.java index c90be60a79..c9340f8d79 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaInRedisConfig.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaRedisConfigImpl.java @@ -1,4 +1,4 @@ -package cn.binarywang.wx.miniapp.config; +package cn.binarywang.wx.miniapp.config.impl; import java.io.File; import java.util.HashMap; @@ -7,6 +7,7 @@ import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; +import cn.binarywang.wx.miniapp.config.WxMaConfig; import com.github.jedis.lock.JedisLock; import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; @@ -17,105 +18,92 @@ /** * 基于Redis的微信配置provider. - * + * *
      * 需要引入依赖jedis-lock,才能使用该类。
      * 
    * * @author winter */ -public class WxMaInRedisConfig implements WxMaConfig { - +public class WxMaRedisConfigImpl implements WxMaConfig { private static final String ACCESS_TOKEN = "accessToken"; private static final String JSAPI_TICKET = "jsapiTicket"; private static final String CARD_API_TICKET = "cardApiTicket"; - + private static final String HASH_VALUE_FIELD = "value"; private static final String HASH_EXPIRE_FIELD = "expire"; - - protected JedisPool jedisPool; + + private JedisPool jedisPool; /** - * 微信小程序唯一id,用于拼接存储到redis时的key,防止key重复 + * 微信小程序唯一id,用于拼接存储到redis时的key,防止key重复. */ - protected String maId; - - protected volatile String msgDataFormat; + private String maId; + + private volatile String msgDataFormat; protected volatile String appid; - protected volatile String secret; + private volatile String secret; protected volatile String token; - protected volatile String aesKey; + private volatile String aesKey; - protected volatile String httpProxyHost; - protected volatile int httpProxyPort; - protected volatile String httpProxyUsername; - protected volatile String httpProxyPassword; + private volatile String httpProxyHost; + private volatile int httpProxyPort; + private volatile String httpProxyUsername; + private volatile String httpProxyPassword; - protected Lock accessTokenLock; - protected Lock jsapiTicketLock; - protected Lock cardApiTicketLock; + private Lock accessTokenLock; + private Lock jsapiTicketLock; + private Lock cardApiTicketLock; /** - * 临时文件目录 + * 临时文件目录. */ protected volatile File tmpDirFile; - protected volatile ApacheHttpClientBuilder apacheHttpClientBuilder; - + private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; + private String getRedisKey(String key) { - StringBuilder redisKey = new StringBuilder("maConfig:"); - if(maId == null) { - return redisKey.append(key).toString(); - } else { - return redisKey.append(maId).append(":").append(key).toString(); - } - } - + StringBuilder redisKey = new StringBuilder("maConfig:"); + if (maId == null) { + return redisKey.append(key).toString(); + } else { + return redisKey.append(maId).append(":").append(key).toString(); + } + } + private String getValueFromRedis(String key) { - Jedis jedis = jedisPool.getResource(); - try { + try (Jedis jedis = jedisPool.getResource()) { return jedis.hget(getRedisKey(key), HASH_VALUE_FIELD); - } finally { - jedis.close(); - } + } } - + private void setValueToRedis(String key, long expiresTime, String value) { - Jedis jedis = jedisPool.getResource(); - try { - Map hash = new HashMap(); - hash.put(HASH_VALUE_FIELD, value); - hash.put(HASH_EXPIRE_FIELD, String.valueOf(expiresTime)); - jedis.hmset(getRedisKey(key), hash); - } finally { - jedis.close(); - } - } - + try (Jedis jedis = jedisPool.getResource()) { + Map hash = new HashMap(); + hash.put(HASH_VALUE_FIELD, value); + hash.put(HASH_EXPIRE_FIELD, String.valueOf(expiresTime)); + jedis.hmset(getRedisKey(key), hash); + } + } + private long getExpireFromRedis(String key) { - Jedis jedis = jedisPool.getResource(); - try { + try (Jedis jedis = jedisPool.getResource()) { String expire = jedis.hget(getRedisKey(key), HASH_EXPIRE_FIELD); - return expire == null ? 0 : Long.valueOf(expire); - } finally { - jedis.close(); - } + return expire == null ? 0 : Long.parseLong(expire); + } } - + private void setExpire(String key, long expiresTime) { - Jedis jedis = jedisPool.getResource(); - try { - jedis.hset(getRedisKey(key), HASH_EXPIRE_FIELD, String.valueOf(expiresTime)); - } finally { - jedis.close(); - } + try (Jedis jedis = jedisPool.getResource()) { + jedis.hset(getRedisKey(key), HASH_EXPIRE_FIELD, String.valueOf(expiresTime)); + } } public void setJedisPool(JedisPool jedisPool) { - this.jedisPool = jedisPool; + this.jedisPool = jedisPool; } public void setMaId(String maId) { - this.maId = maId; + this.maId = maId; } @Override @@ -125,19 +113,19 @@ public String getAccessToken() { @Override public Lock getAccessTokenLock() { - if(accessTokenLock == null) { - synchronized (this) { - if(accessTokenLock == null) { - accessTokenLock = new DistributedLock(getRedisKey("accessTokenLock")); - } - } - } + if (accessTokenLock == null) { + synchronized (this) { + if (accessTokenLock == null) { + accessTokenLock = new DistributedLock(getRedisKey("accessTokenLock")); + } + } + } return accessTokenLock; } @Override public boolean isAccessTokenExpired() { - return System.currentTimeMillis() > getExpireFromRedis(ACCESS_TOKEN); + return System.currentTimeMillis() > getExpireFromRedis(ACCESS_TOKEN); } @Override @@ -147,7 +135,7 @@ public synchronized void updateAccessToken(WxAccessToken accessToken) { @Override public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { - setValueToRedis(ACCESS_TOKEN, System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L, accessToken); + setValueToRedis(ACCESS_TOKEN, System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L, accessToken); } @Override @@ -157,30 +145,30 @@ public String getJsapiTicket() { @Override public Lock getJsapiTicketLock() { - if(jsapiTicketLock == null) { - synchronized (this) { - if(jsapiTicketLock == null) { - jsapiTicketLock = new DistributedLock(getRedisKey("jsapiTicketLock")); - } - } - } + if (jsapiTicketLock == null) { + synchronized (this) { + if (jsapiTicketLock == null) { + jsapiTicketLock = new DistributedLock(getRedisKey("jsapiTicketLock")); + } + } + } return jsapiTicketLock; } @Override public boolean isJsapiTicketExpired() { - return System.currentTimeMillis() > getExpireFromRedis(JSAPI_TICKET); + return System.currentTimeMillis() > getExpireFromRedis(JSAPI_TICKET); } @Override public void expireJsapiTicket() { - setExpire(JSAPI_TICKET, 0); + setExpire(JSAPI_TICKET, 0); } @Override public void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { - // 预留200秒的时间 - setValueToRedis(JSAPI_TICKET, System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L, jsapiTicket); + // 预留200秒的时间 + setValueToRedis(JSAPI_TICKET, System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L, jsapiTicket); } @@ -191,34 +179,34 @@ public String getCardApiTicket() { @Override public Lock getCardApiTicketLock() { - if(cardApiTicketLock == null) { - synchronized (this) { - if(cardApiTicketLock == null) { - cardApiTicketLock = new DistributedLock(getRedisKey("cardApiTicketLock")); - } - } - } + if (cardApiTicketLock == null) { + synchronized (this) { + if (cardApiTicketLock == null) { + cardApiTicketLock = new DistributedLock(getRedisKey("cardApiTicketLock")); + } + } + } return cardApiTicketLock; } @Override public boolean isCardApiTicketExpired() { - return System.currentTimeMillis() > getExpireFromRedis(CARD_API_TICKET); + return System.currentTimeMillis() > getExpireFromRedis(CARD_API_TICKET); } @Override public void expireCardApiTicket() { - setExpire(CARD_API_TICKET, 0); + setExpire(CARD_API_TICKET, 0); } @Override public void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) { - setValueToRedis(CARD_API_TICKET, System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L, cardApiTicket); + setValueToRedis(CARD_API_TICKET, System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L, cardApiTicket); } @Override public void expireAccessToken() { - setExpire(ACCESS_TOKEN, 0); + setExpire(ACCESS_TOKEN, 0); } @Override @@ -241,7 +229,7 @@ public void setToken(String token) { @Override public long getExpiresTime() { - return getExpireFromRedis(ACCESS_TOKEN); + return getExpireFromRedis(ACCESS_TOKEN); } @Override @@ -325,80 +313,65 @@ public String getAppid() { public void setAppid(String appid) { this.appid = appid; } - + /** - * 基于redis的简单分布式锁 + * 基于redis的简单分布式锁. */ private class DistributedLock implements Lock { - - private JedisLock lock; - - private DistributedLock(String key) { - this.lock = new JedisLock(getRedisKey(key)); - } - - @Override - public void lock() { - Jedis jedis = jedisPool.getResource(); - try { - if(!lock.acquire(jedis)) { - throw new RuntimeException("acquire timeouted"); - } - } catch (InterruptedException e) { - throw new RuntimeException("lock failed",e); - } finally { - jedis.close(); - } - } - - @Override - public void lockInterruptibly() throws InterruptedException { - Jedis jedis = jedisPool.getResource(); - try { - if(!lock.acquire(jedis)) { - throw new RuntimeException("acquire timeouted"); - } - } finally { - jedis.close(); - } - } - - @Override - public boolean tryLock() { - Jedis jedis = jedisPool.getResource(); - try { - return lock.acquire(jedis); - } catch (InterruptedException e) { - throw new RuntimeException("lock failed",e); - } finally { - jedis.close(); - } - } - - @Override - public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { - Jedis jedis = jedisPool.getResource(); - try { - return lock.acquire(jedis); - } finally { - jedis.close(); - } - } - - @Override - public void unlock() { - Jedis jedis = jedisPool.getResource(); - try { - lock.release(jedis); - } finally { - jedis.close(); - } - } - - @Override - public Condition newCondition() { - throw new RuntimeException("unsupported method"); - } - + + private JedisLock lock; + + private DistributedLock(String key) { + this.lock = new JedisLock(getRedisKey(key)); + } + + @Override + public void lock() { + try (Jedis jedis = jedisPool.getResource()) { + if (!lock.acquire(jedis)) { + throw new RuntimeException("acquire timeouted"); + } + } catch (InterruptedException e) { + throw new RuntimeException("lock failed", e); + } + } + + @Override + public void lockInterruptibly() throws InterruptedException { + try (Jedis jedis = jedisPool.getResource()) { + if (!lock.acquire(jedis)) { + throw new RuntimeException("acquire timeouted"); + } + } + } + + @Override + public boolean tryLock() { + try (Jedis jedis = jedisPool.getResource()) { + return lock.acquire(jedis); + } catch (InterruptedException e) { + throw new RuntimeException("lock failed", e); + } + } + + @Override + public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { + try (Jedis jedis = jedisPool.getResource()) { + return lock.acquire(jedis); + } + } + + @Override + public void unlock() { + try (Jedis jedis = jedisPool.getResource()) { + lock.release(jedis); + } + } + + @Override + public Condition newCondition() { + throw new RuntimeException("unsupported method"); + } + } } 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 6cebdeb24b..a9dd465612 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 @@ -1,6 +1,6 @@ package cn.binarywang.wx.miniapp.test; -import cn.binarywang.wx.miniapp.config.WxMaInMemoryConfig; +import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.annotations.XStreamAlias; import me.chanjar.weixin.common.util.xml.XStreamInitializer; @@ -13,7 +13,7 @@ * @author Binary Wang */ @XStreamAlias("xml") -public class TestConfig extends WxMaInMemoryConfig { +public class TestConfig extends WxMaDefaultConfigImpl { private String openid; private String kfAccount; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java index f9d4399a60..be8000d339 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java @@ -10,6 +10,7 @@ import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult; import me.chanjar.weixin.mp.bean.result.WxMpUser; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.enums.TicketType; import me.chanjar.weixin.mp.enums.WxMpApiUrl; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java index 8b854ebbaf..f7969eae75 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java @@ -22,6 +22,7 @@ import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult; import me.chanjar.weixin.mp.bean.result.WxMpUser; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.enums.TicketType; import me.chanjar.weixin.mp.enums.WxMpApiUrl; import me.chanjar.weixin.mp.util.WxMpConfigStorageHolder; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java index 17aec251f7..d13a95b16f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java @@ -7,7 +7,7 @@ import me.chanjar.weixin.common.util.http.HttpType; 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.mp.config.WxMpConfigStorage; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java index ee1074b508..a4aeac5add 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java @@ -7,7 +7,7 @@ import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.HttpType; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import java.util.concurrent.locks.Lock; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java index f1c1193c12..f7f2a8e7af 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java @@ -6,7 +6,7 @@ import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.HttpType; import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import okhttp3.*; import java.io.IOException; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpSubscribeMsgServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpSubscribeMsgServiceImpl.java index b9c5d4fd3c..ff99b12c83 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpSubscribeMsgServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpSubscribeMsgServiceImpl.java @@ -3,7 +3,7 @@ import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.URIUtil; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpSubscribeMsgService; import me.chanjar.weixin.mp.bean.subscribe.WxMpSubscribeMessage; 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 f8ed19bce4..bb93976f31 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 @@ -15,7 +15,7 @@ import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.util.XmlUtils; import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.util.crypto.WxMpCryptUtil; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; import me.chanjar.weixin.mp.util.xml.XStreamTransformer; @@ -527,10 +527,10 @@ public class WxMpXmlMessage implements Serializable { @XStreamAlias("DeviceID") @XStreamConverter(value = XStreamCDataConverter.class) private String deviceId; - + /** * 微信客户端生成的session id,用于request和response对应, - * 因此响应中该字段第三方需要原封不变的带回 + * 因此响应中该字段第三方需要原封不变的带回 */ @XStreamAlias("SessionID") @XStreamConverter(value = XStreamCDataConverter.class) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutMessage.java index 74b053f17d..40e0b41a2b 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlOutMessage.java @@ -4,7 +4,7 @@ import com.thoughtworks.xstream.annotations.XStreamConverter; import lombok.Data; import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.builder.outxml.*; import me.chanjar.weixin.mp.util.crypto.WxMpCryptUtil; import me.chanjar.weixin.mp.util.xml.XStreamTransformer; @@ -79,7 +79,7 @@ public static NewsBuilder NEWS() { public static TransferCustomerServiceBuilder TRANSFER_CUSTOMER_SERVICE() { return new TransferCustomerServiceBuilder(); } - + /** * 获得设备消息builder */ diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/WxMpConfigStorage.java similarity index 98% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/WxMpConfigStorage.java index bd5476d473..7c3c46292f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/WxMpConfigStorage.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.mp.api; +package me.chanjar.weixin.mp.config; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; 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/config/impl/WxMpDefaultConfigImpl.java similarity index 96% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/impl/WxMpDefaultConfigImpl.java index 31eca6a4e2..08e7d0830c 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/config/impl/WxMpDefaultConfigImpl.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.mp.api; +package me.chanjar.weixin.mp.config.impl; import java.io.File; import java.io.Serializable; @@ -8,6 +8,7 @@ import lombok.Data; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.bean.WxMpHostConfig; import me.chanjar.weixin.mp.enums.TicketType; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; @@ -18,7 +19,7 @@ * @author chanjarster */ @Data -public class WxMpInMemoryConfigStorage implements WxMpConfigStorage, Serializable { +public class WxMpDefaultConfigImpl implements WxMpConfigStorage, Serializable { private static final long serialVersionUID = -6646519023303395185L; protected volatile String appId; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInRedisConfigStorage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/impl/WxMpRedisConfigImpl.java similarity index 92% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInRedisConfigStorage.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/impl/WxMpRedisConfigImpl.java index b1ff3f1f87..4d2d1783ed 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInRedisConfigStorage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/impl/WxMpRedisConfigImpl.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.mp.api; +package me.chanjar.weixin.mp.config.impl; import me.chanjar.weixin.mp.enums.TicketType; import redis.clients.jedis.Jedis; @@ -15,17 +15,17 @@ * @author nickwong */ @SuppressWarnings("hiding") -public class WxMpInRedisConfigStorage extends WxMpInMemoryConfigStorage { +public class WxMpRedisConfigImpl extends WxMpDefaultConfigImpl { private static final String ACCESS_TOKEN_KEY = "wx:access_token:"; /** * 使用连接池保证线程安全. */ - protected final JedisPool jedisPool; + private final JedisPool jedisPool; private String accessTokenKey; - public WxMpInRedisConfigStorage(JedisPool jedisPool) { + public WxMpRedisConfigImpl(JedisPool jedisPool) { this.jedisPool = jedisPool; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java index 22aeaa0bb5..77124c688f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java @@ -1,7 +1,7 @@ package me.chanjar.weixin.mp.enums; import lombok.AllArgsConstructor; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import static me.chanjar.weixin.mp.bean.WxMpHostConfig.*; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java index d95e8f8f3d..945219acf5 100755 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java @@ -17,7 +17,7 @@ */ package me.chanjar.weixin.mp.util.crypto; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import org.apache.commons.codec.binary.Base64; public class WxMpCryptUtil extends me.chanjar.weixin.common.util.crypto.WxCryptUtil { diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImplTest.java index 7c36930b0a..a434144cc1 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImplTest.java @@ -7,7 +7,7 @@ import com.google.inject.Inject; import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.error.WxErrorException; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.test.ApiTestModule; import me.chanjar.weixin.mp.api.test.TestConfigStorage; diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java index 29c8d2e2b8..cc964e80fd 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java @@ -12,7 +12,7 @@ import com.google.inject.Module; import com.thoughtworks.xstream.XStream; import me.chanjar.weixin.common.util.xml.XStreamInitializer; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; public class ApiTestModule implements Module { diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/TestConfigStorage.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/TestConfigStorage.java index ed6c5cb168..5266beb237 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/TestConfigStorage.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/TestConfigStorage.java @@ -1,13 +1,13 @@ package me.chanjar.weixin.mp.api.test; import com.thoughtworks.xstream.annotations.XStreamAlias; -import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage; +import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl; import org.apache.commons.lang3.builder.ToStringBuilder; import java.util.concurrent.locks.Lock; @XStreamAlias("xml") -public class TestConfigStorage extends WxMpInMemoryConfigStorage { +public class TestConfigStorage extends WxMpDefaultConfigImpl { private String openid; private String kfAccount; diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoInMemoryConfigStorage.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoInMemoryConfigStorage.java index 30d36920bd..535123bdd7 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoInMemoryConfigStorage.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoInMemoryConfigStorage.java @@ -6,13 +6,13 @@ import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.annotations.XStreamAlias; import me.chanjar.weixin.common.util.xml.XStreamInitializer; -import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage; +import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl; /** * @author Daniel Qian */ @XStreamAlias("xml") -class WxMpDemoInMemoryConfigStorage extends WxMpInMemoryConfigStorage { +class WxMpDemoInMemoryConfigStorage extends WxMpDefaultConfigImpl { private static final long serialVersionUID = -3706236839197109704L; public static WxMpDemoInMemoryConfigStorage fromXml(InputStream is) { diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java index 5d85d64c05..36f81ae4cc 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java @@ -1,7 +1,7 @@ package me.chanjar.weixin.mp.demo; import me.chanjar.weixin.common.api.WxConsts; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpMessageHandler; import me.chanjar.weixin.mp.api.WxMpMessageRouter; import me.chanjar.weixin.mp.api.WxMpService; diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpEndpointServlet.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpEndpointServlet.java index 3f32d9c94a..e835e6375c 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpEndpointServlet.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpEndpointServlet.java @@ -1,6 +1,6 @@ package me.chanjar.weixin.mp.demo; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpMessageRouter; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; 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 066cf8c00f..40833c1b98 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 @@ -2,7 +2,7 @@ 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.mp.config.WxMpConfigStorage; import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken; import me.chanjar.weixin.open.bean.WxOpenComponentAccessToken; 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 ef699212bf..80882b0c47 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 @@ -10,7 +10,7 @@ import cn.binarywang.wx.miniapp.config.WxMaConfig; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.bean.WxMpHostConfig; import me.chanjar.weixin.mp.enums.TicketType; import me.chanjar.weixin.open.api.WxOpenConfigStorage; diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java index a29703df16..aa845fb223 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java @@ -1,7 +1,7 @@ package me.chanjar.weixin.open.api.impl; import me.chanjar.weixin.common.error.WxErrorException; -import me.chanjar.weixin.mp.api.WxMpConfigStorage; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; import me.chanjar.weixin.open.api.WxOpenComponentService; 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 d9b7b49553..24ee39cc30 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 @@ -6,7 +6,6 @@ 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; From ae4a0211cd5c67c7dfae2b0a94c995ee177fc642 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Mon, 5 Aug 2019 16:47:03 +0800 Subject: [PATCH 63/74] =?UTF-8?q?:white=5Fcheck=5Fmark:=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E7=82=B9=E6=B5=8B=E8=AF=95=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../menu/WxMpGetSelfMenuInfoResultTest.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/menu/WxMpGetSelfMenuInfoResultTest.java diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/menu/WxMpGetSelfMenuInfoResultTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/menu/WxMpGetSelfMenuInfoResultTest.java new file mode 100644 index 0000000000..3df5742704 --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/menu/WxMpGetSelfMenuInfoResultTest.java @@ -0,0 +1,28 @@ +package me.chanjar.weixin.mp.bean.menu; + +import org.testng.annotations.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.testng.Assert.*; + +/** + * @author Binary Wang + * @date 2019-08-05 + */ +public class WxMpGetSelfMenuInfoResultTest { + + @Test + public void testFromJson() { + String json = "{\"is_menu_open\":1,\"selfmenu_info\":{\"button\":[{\"name\":\"学院\",\"sub_button\":{\"list\":[{\"type\":\"miniprogram\",\"name\":\"成语答题王\",\"url\":\"http:\\/\\/host\",\"appid\":\"wxf4dc5b4e7b35dcd1\",\"pagepath\":\"pages\\/index\\/index\"},{\"type\":\"miniprogram\",\"name\":\"大师课程\",\"url\":\"https:\\/\\/host\\/course\\/tutorial\",\"appid\":\"wxfd6acd566482c6cb\",\"pagepath\":\"pages\\/tutorialDetail\\/tutorialDetail\"}]}},{\"type\":\"miniprogram\",\"name\":\"学科商城\",\"url\":\"https:\\/\\/host\\/-dAEuY\",\"appid\":\"wx720f9f1301595564\",\"pagepath\":\"pages\\/home\\/dashboard\\/index\"}]}}"; + final WxMpGetSelfMenuInfoResult selfMenuInfoResult = WxMpGetSelfMenuInfoResult.fromJson(json); + assertThat(selfMenuInfoResult).isNotNull(); + assertThat(selfMenuInfoResult.getIsMenuOpen()).isEqualTo(1); + assertThat(selfMenuInfoResult.getSelfMenuInfo()).isNotNull(); + final List buttons = selfMenuInfoResult.getSelfMenuInfo().getButtons(); + assertThat(buttons.size()).isEqualTo(2); + assertThat(buttons.get(1).getAppId()).isEqualTo("wx720f9f1301595564"); + assertThat(buttons.get(1).getPagePath()).isEqualTo("pages/home/dashboard/index"); + } +} From 9de72c76238e5760d4cda4969e055b50028c7ae7 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Thu, 8 Aug 2019 18:07:43 +0800 Subject: [PATCH 64/74] =?UTF-8?q?:art:=20=E4=BC=98=E5=8C=96=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/util/crypto/WxCryptUtil.java | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java index 8124148110..3c5750e621 100755 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java @@ -55,20 +55,19 @@ public WxCryptUtil() { } /** - * 构造函数 + * 构造函数. * * @param token 公众平台上,开发者设置的token * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey * @param appidOrCorpid 公众平台appid/corpid */ - public WxCryptUtil(String token, String encodingAesKey, - String appidOrCorpid) { + public WxCryptUtil(String token, String encodingAesKey, String appidOrCorpid) { this.token = token; this.appidOrCorpid = appidOrCorpid; this.aesKey = Base64.decodeBase64(encodingAesKey + "="); } - static String extractEncryptPart(String xml) { + private static String extractEncryptPart(String xml) { try { DocumentBuilder db = BUILDER_LOCAL.get(); Document document = db.parse(new InputSource(new StringReader(xml))); @@ -81,7 +80,7 @@ static String extractEncryptPart(String xml) { } /** - * 将一个数字转换成生成4个字节的网络字节序bytes数组 + * 将一个数字转换成生成4个字节的网络字节序bytes数组. */ private static byte[] number2BytesInNetworkOrder(int number) { byte[] orderBytes = new byte[4]; @@ -93,7 +92,7 @@ private static byte[] number2BytesInNetworkOrder(int number) { } /** - * 4个字节的网络字节序bytes数组还原成一个数字 + * 4个字节的网络字节序bytes数组还原成一个数字. */ private static int bytesNetworkOrder2Number(byte[] bytesInNetworkOrder) { int sourceNumber = 0; @@ -105,7 +104,7 @@ private static int bytesNetworkOrder2Number(byte[] bytesInNetworkOrder) { } /** - * 随机生成16位字符串 + * 随机生成16位字符串. */ private static String genRandomStr() { String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; @@ -119,7 +118,7 @@ private static String genRandomStr() { } /** - * 生成xml消息 + * 生成xml消息. * * @param encrypt 加密后的消息密文 * @param signature 安全签名 @@ -127,8 +126,7 @@ private static String genRandomStr() { * @param nonce 随机字符串 * @return 生成的xml字符串 */ - private static String generateXml(String encrypt, String signature, - String timestamp, String nonce) { + private static String generateXml(String encrypt, String signature, String timestamp, String nonce) { String format = "\n" + "\n" + "\n" + "%3$s\n" + "\n" @@ -242,10 +240,9 @@ public String decrypt(String cipherText) { try { // 设置解密模式为AES的CBC模式 Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); - SecretKeySpec key_spec = new SecretKeySpec(this.aesKey, "AES"); - IvParameterSpec iv = new IvParameterSpec( - Arrays.copyOfRange(this.aesKey, 0, 16)); - cipher.init(Cipher.DECRYPT_MODE, key_spec, iv); + SecretKeySpec keySpec = new SecretKeySpec(this.aesKey, "AES"); + IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(this.aesKey, 0, 16)); + cipher.init(Cipher.DECRYPT_MODE, keySpec, iv); // 使用BASE64对密文进行解码 byte[] encrypted = Base64.decodeBase64(cipherText); @@ -256,7 +253,8 @@ public String decrypt(String cipherText) { throw new RuntimeException(e); } - String xmlContent, fromAppid; + String xmlContent; + String fromAppid; try { // 去除补位字符 byte[] bytes = PKCS7Encoder.decode(original); @@ -266,17 +264,15 @@ public String decrypt(String cipherText) { int xmlLength = bytesNetworkOrder2Number(networkOrder); - xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), - CHARSET); - fromAppid = new String( - Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET); + xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET); + fromAppid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET); } catch (Exception e) { throw new RuntimeException(e); } // appid不相同的情况 if (!fromAppid.equals(this.appidOrCorpid)) { - throw new RuntimeException("AppID不正确"); + throw new RuntimeException("AppID不正确,请核实!"); } return xmlContent; From 2f372b4a398b70d6afb3e8bef2509edc4a111ef2 Mon Sep 17 00:00:00 2001 From: Ziyear <31235089+Ziyear@users.noreply.github.com> Date: Fri, 9 Aug 2019 09:26:46 +0800 Subject: [PATCH 65/74] =?UTF-8?q?:bug:=20#1148=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E6=94=AF=E4=BB=98=E6=8B=89=E5=8F=96=E8=AF=84?= =?UTF-8?q?=E8=AE=BA=E4=BF=A1=E6=81=AF=E6=8E=A5=E5=8F=A3=E7=AD=BE=E5=90=8D?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 01578a23a5..9e0e57c122 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 @@ -779,8 +779,8 @@ public String queryComment(Date beginDate, Date endDate, Integer offset, Integer @Override public String queryComment(WxPayQueryCommentRequest request) throws WxPayException { - request.checkAndSign(this.getConfig()); request.setSignType(SignType.HMAC_SHA256); + request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/billcommentsp/batchquerycomment"; String responseContent = this.post(url, request.toXML(), true); From 2ccb60fe62d6e5870a22c6ab2e3820bb214eb0d5 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Fri, 9 Aug 2019 09:42:59 +0800 Subject: [PATCH 66/74] =?UTF-8?q?:art:=20=E5=A2=9E=E5=8A=A0=E7=82=B9?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 9e0e57c122..d2805c0687 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 @@ -779,7 +779,7 @@ public String queryComment(Date beginDate, Date endDate, Integer offset, Integer @Override public String queryComment(WxPayQueryCommentRequest request) throws WxPayException { - request.setSignType(SignType.HMAC_SHA256); + request.setSignType(SignType.HMAC_SHA256);// 签名类型,目前仅支持HMAC-SHA256,默认就是HMAC-SHA256 request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/billcommentsp/batchquerycomment"; From 44b3680a3fd2060f9470b061dcaae5d05a2bcf53 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 10 Aug 2019 17:36:57 +0800 Subject: [PATCH 67/74] =?UTF-8?q?:hammer:=20=E9=87=8D=E6=9E=84=E5=8C=85?= =?UTF-8?q?=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wxjava/mp/{ => config}/WxMpAutoConfiguration.java | 3 ++- .../mp/{ => config}/WxMpServiceAutoConfiguration.java | 2 +- .../mp/{ => config}/WxMpStorageAutoConfiguration.java | 4 +++- .../starter/wxjava/mp/{ => properties}/RedisProperties.java | 4 ++-- .../starter/wxjava/mp/{ => properties}/WxMpProperties.java | 6 +++--- .../src/main/resources/META-INF/spring.factories | 2 +- 6 files changed, 12 insertions(+), 9 deletions(-) rename starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/{ => config}/WxMpAutoConfiguration.java (74%) rename starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/{ => config}/WxMpServiceAutoConfiguration.java (98%) rename starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/{ => config}/WxMpStorageAutoConfiguration.java (93%) rename starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/{ => properties}/RedisProperties.java (90%) rename starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/{ => properties}/WxMpProperties.java (78%) diff --git a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/WxMpAutoConfiguration.java b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpAutoConfiguration.java similarity index 74% rename from starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/WxMpAutoConfiguration.java rename to starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpAutoConfiguration.java index ba85d04482..42fcaf3a53 100644 --- a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/WxMpAutoConfiguration.java +++ b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpAutoConfiguration.java @@ -1,5 +1,6 @@ -package com.binarywang.spring.starter.wxjava.mp; +package com.binarywang.spring.starter.wxjava.mp.config; +import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; diff --git a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/WxMpServiceAutoConfiguration.java b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpServiceAutoConfiguration.java similarity index 98% rename from starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/WxMpServiceAutoConfiguration.java rename to starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpServiceAutoConfiguration.java index a5234ed769..9d2b94765d 100644 --- a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/WxMpServiceAutoConfiguration.java +++ b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpServiceAutoConfiguration.java @@ -1,4 +1,4 @@ -package com.binarywang.spring.starter.wxjava.mp; +package com.binarywang.spring.starter.wxjava.mp.config; import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; diff --git a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/WxMpStorageAutoConfiguration.java b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpStorageAutoConfiguration.java similarity index 93% rename from starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/WxMpStorageAutoConfiguration.java rename to starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpStorageAutoConfiguration.java index d70d88c878..1c91716295 100644 --- a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/WxMpStorageAutoConfiguration.java +++ b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpStorageAutoConfiguration.java @@ -1,5 +1,7 @@ -package com.binarywang.spring.starter.wxjava.mp; +package com.binarywang.spring.starter.wxjava.mp.config; +import com.binarywang.spring.starter.wxjava.mp.properties.RedisProperties; +import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties; import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl; import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl; diff --git a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/RedisProperties.java b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/RedisProperties.java similarity index 90% rename from starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/RedisProperties.java rename to starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/RedisProperties.java index d609cc88c1..0f0aeca96c 100644 --- a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/RedisProperties.java +++ b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/RedisProperties.java @@ -1,4 +1,4 @@ -package com.binarywang.spring.starter.wxjava.mp; +package com.binarywang.spring.starter.wxjava.mp.properties; import lombok.Data; @@ -39,4 +39,4 @@ public class RedisProperties implements Serializable { private Integer maxIdle; private Integer maxWaitMillis; private Integer minIdle; -} \ No newline at end of file +} diff --git a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/WxMpProperties.java b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/WxMpProperties.java similarity index 78% rename from starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/WxMpProperties.java rename to starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/WxMpProperties.java index af74f430ed..085916cdad 100644 --- a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/WxMpProperties.java +++ b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/WxMpProperties.java @@ -1,12 +1,12 @@ -package com.binarywang.spring.starter.wxjava.mp; +package com.binarywang.spring.starter.wxjava.mp.properties; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import java.io.Serializable; -import static com.binarywang.spring.starter.wxjava.mp.WxMpProperties.PREFIX; -import static com.binarywang.spring.starter.wxjava.mp.WxMpProperties.StorageType.memory; +import static com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties.PREFIX; +import static com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties.StorageType.memory; /** diff --git a/starters/wx-java-mp-starter/src/main/resources/META-INF/spring.factories b/starters/wx-java-mp-starter/src/main/resources/META-INF/spring.factories index aaa17f7676..6634593ff2 100644 --- a/starters/wx-java-mp-starter/src/main/resources/META-INF/spring.factories +++ b/starters/wx-java-mp-starter/src/main/resources/META-INF/spring.factories @@ -1 +1 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.binarywang.spring.starter.wxjava.mp.WxMpAutoConfiguration \ No newline at end of file +org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.binarywang.spring.starter.wxjava.mp.config.WxMpAutoConfiguration From 3a1fae639a94cb7866d5368ee2bff45c855d3f11 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 10 Aug 2019 17:43:14 +0800 Subject: [PATCH 68/74] =?UTF-8?q?:hammer:=20=E8=A7=84=E8=8C=83=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mp/config/WxMpAutoConfiguration.java | 5 + .../config/WxMpServiceAutoConfiguration.java | 66 +++++----- .../config/WxMpStorageAutoConfiguration.java | 114 +++++++++--------- .../wxjava/mp/properties/RedisProperties.java | 65 +++++----- .../wxjava/mp/properties/WxMpProperties.java | 24 ++-- 5 files changed, 148 insertions(+), 126 deletions(-) diff --git a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpAutoConfiguration.java b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpAutoConfiguration.java index 42fcaf3a53..e2b0a60d2b 100644 --- a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpAutoConfiguration.java +++ b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpAutoConfiguration.java @@ -5,6 +5,11 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +/** + * . + * + * @author someone + */ @Configuration @EnableConfigurationProperties(WxMpProperties.class) @Import({WxMpStorageAutoConfiguration.class, WxMpServiceAutoConfiguration.class}) diff --git a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpServiceAutoConfiguration.java b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpServiceAutoConfiguration.java index 9d2b94765d..c39402ac72 100644 --- a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpServiceAutoConfiguration.java +++ b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpServiceAutoConfiguration.java @@ -12,42 +12,44 @@ import org.springframework.context.annotation.Configuration; /** - * 微信公众号相关服务自动注册 + * 微信公众号相关服务自动注册. + * + * @author someone */ @Configuration public class WxMpServiceAutoConfiguration { - @Autowired - private ApplicationContext ctx; + @Autowired + private ApplicationContext ctx; - @Bean - @ConditionalOnMissingBean - public WxMpService wxMpService(WxMpConfigStorage configStorage) { - WxMpService wxMpService = new WxMpServiceImpl(); - wxMpService.setWxMpConfigStorage(configStorage); - registerWxMpSubService(wxMpService); - return wxMpService; - } + @Bean + @ConditionalOnMissingBean + public WxMpService wxMpService(WxMpConfigStorage configStorage) { + WxMpService wxMpService = new WxMpServiceImpl(); + wxMpService.setWxMpConfigStorage(configStorage); + registerWxMpSubService(wxMpService); + return wxMpService; + } - @ConditionalOnBean(WxMpService.class) - public Object registerWxMpSubService(WxMpService wxMpService) { - ConfigurableListableBeanFactory factory = (ConfigurableListableBeanFactory) ctx.getAutowireCapableBeanFactory(); - factory.registerSingleton("wxMpKefuService", wxMpService.getKefuService()); - factory.registerSingleton("wxMpMaterialService", wxMpService.getMaterialService()); - factory.registerSingleton("wxMpMenuService", wxMpService.getMenuService()); - factory.registerSingleton("wxMpUserService", wxMpService.getUserService()); - factory.registerSingleton("wxMpUserTagService", wxMpService.getUserTagService()); - factory.registerSingleton("wxMpQrcodeService", wxMpService.getQrcodeService()); - factory.registerSingleton("wxMpCardService", wxMpService.getCardService()); - factory.registerSingleton("wxMpDataCubeService", wxMpService.getDataCubeService()); - factory.registerSingleton("wxMpUserBlacklistService", wxMpService.getBlackListService()); - factory.registerSingleton("wxMpStoreService", wxMpService.getStoreService()); - factory.registerSingleton("wxMpTemplateMsgService", wxMpService.getTemplateMsgService()); - factory.registerSingleton("wxMpSubscribeMsgService", wxMpService.getSubscribeMsgService()); - factory.registerSingleton("wxMpDeviceService", wxMpService.getDeviceService()); - factory.registerSingleton("wxMpShakeService", wxMpService.getShakeService()); - factory.registerSingleton("wxMpMemberCardService", wxMpService.getMemberCardService()); - factory.registerSingleton("wxMpMassMessageService", wxMpService.getMassMessageService()); - return Boolean.TRUE; - } + @ConditionalOnBean(WxMpService.class) + public Object registerWxMpSubService(WxMpService wxMpService) { + ConfigurableListableBeanFactory factory = (ConfigurableListableBeanFactory) ctx.getAutowireCapableBeanFactory(); + factory.registerSingleton("wxMpKefuService", wxMpService.getKefuService()); + factory.registerSingleton("wxMpMaterialService", wxMpService.getMaterialService()); + factory.registerSingleton("wxMpMenuService", wxMpService.getMenuService()); + factory.registerSingleton("wxMpUserService", wxMpService.getUserService()); + factory.registerSingleton("wxMpUserTagService", wxMpService.getUserTagService()); + factory.registerSingleton("wxMpQrcodeService", wxMpService.getQrcodeService()); + factory.registerSingleton("wxMpCardService", wxMpService.getCardService()); + factory.registerSingleton("wxMpDataCubeService", wxMpService.getDataCubeService()); + factory.registerSingleton("wxMpUserBlacklistService", wxMpService.getBlackListService()); + factory.registerSingleton("wxMpStoreService", wxMpService.getStoreService()); + factory.registerSingleton("wxMpTemplateMsgService", wxMpService.getTemplateMsgService()); + factory.registerSingleton("wxMpSubscribeMsgService", wxMpService.getSubscribeMsgService()); + factory.registerSingleton("wxMpDeviceService", wxMpService.getDeviceService()); + factory.registerSingleton("wxMpShakeService", wxMpService.getShakeService()); + factory.registerSingleton("wxMpMemberCardService", wxMpService.getMemberCardService()); + factory.registerSingleton("wxMpMassMessageService", wxMpService.getMassMessageService()); + return Boolean.TRUE; + } } diff --git a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpStorageAutoConfiguration.java b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpStorageAutoConfiguration.java index 1c91716295..18024707a4 100644 --- a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpStorageAutoConfiguration.java +++ b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpStorageAutoConfiguration.java @@ -2,6 +2,7 @@ import com.binarywang.spring.starter.wxjava.mp.properties.RedisProperties; import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.mp.config.WxMpConfigStorage; import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl; import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl; @@ -13,74 +14,75 @@ import redis.clients.jedis.JedisPoolConfig; /** - * 微信公众号存储策略自动配置 + * 微信公众号存储策略自动配置. + * + * @author someone */ @Configuration +@RequiredArgsConstructor public class WxMpStorageAutoConfiguration { + private final WxMpProperties properties; - @Autowired - private WxMpProperties properties; + @Autowired(required = false) + private JedisPool jedisPool; - @Autowired(required = false) - private JedisPool jedisPool; + @Bean + @ConditionalOnMissingBean(WxMpConfigStorage.class) + public WxMpConfigStorage wxMpInMemoryConfigStorage() { + WxMpProperties.ConfigStorage storage = properties.getConfigStorage(); + WxMpProperties.StorageType type = storage.getType(); - @Bean - @ConditionalOnMissingBean(WxMpConfigStorage.class) - public WxMpConfigStorage wxMpInMemoryConfigStorage() { - WxMpProperties.ConfigStorage storage = properties.getConfigStorage(); - WxMpProperties.StorageType type = storage.getType(); - - if (type == WxMpProperties.StorageType.redis) { - return getWxMpInRedisConfigStorage(); - } - return getWxMpInMemoryConfigStorage(); - } - - private WxMpDefaultConfigImpl getWxMpInMemoryConfigStorage() { - WxMpDefaultConfigImpl config = new WxMpDefaultConfigImpl(); - setWxMpInfo(config); - return config; + if (type == WxMpProperties.StorageType.redis) { + return getWxMpInRedisConfigStorage(); } + return getWxMpInMemoryConfigStorage(); + } - private WxMpRedisConfigImpl getWxMpInRedisConfigStorage() { - JedisPool poolToUse = jedisPool; - if (poolToUse == null) { - poolToUse = getJedisPool(); - } - WxMpRedisConfigImpl config = new WxMpRedisConfigImpl(poolToUse); - setWxMpInfo(config); - return config; - } + private WxMpDefaultConfigImpl getWxMpInMemoryConfigStorage() { + WxMpDefaultConfigImpl config = new WxMpDefaultConfigImpl(); + setWxMpInfo(config); + return config; + } - private void setWxMpInfo(WxMpDefaultConfigImpl config) { - config.setAppId(properties.getAppId()); - config.setSecret(properties.getSecret()); - config.setToken(properties.getToken()); - config.setAesKey(properties.getAesKey()); + private WxMpRedisConfigImpl getWxMpInRedisConfigStorage() { + JedisPool poolToUse = jedisPool; + if (poolToUse == null) { + poolToUse = getJedisPool(); } + WxMpRedisConfigImpl config = new WxMpRedisConfigImpl(poolToUse); + setWxMpInfo(config); + return config; + } - private JedisPool getJedisPool() { - WxMpProperties.ConfigStorage storage = properties.getConfigStorage(); - RedisProperties redis = storage.getRedis(); + private void setWxMpInfo(WxMpDefaultConfigImpl config) { + config.setAppId(properties.getAppId()); + config.setSecret(properties.getSecret()); + config.setToken(properties.getToken()); + config.setAesKey(properties.getAesKey()); + } - JedisPoolConfig config = new JedisPoolConfig(); - if (redis.getMaxActive() != null) { - config.setMaxTotal(redis.getMaxActive()); - } - if (redis.getMaxIdle() != null) { - config.setMaxIdle(redis.getMaxIdle()); - } - if (redis.getMaxWaitMillis() != null) { - config.setMaxWaitMillis(redis.getMaxWaitMillis()); - } - if (redis.getMinIdle() != null) { - config.setMinIdle(redis.getMinIdle()); - } - config.setTestOnBorrow(true); - config.setTestWhileIdle(true); + private JedisPool getJedisPool() { + WxMpProperties.ConfigStorage storage = properties.getConfigStorage(); + RedisProperties redis = storage.getRedis(); - JedisPool pool = new JedisPool(config, redis.getHost(), redis.getPort(), - redis.getTimeout(), redis.getPassword(), redis.getDatabase()); - return pool; + JedisPoolConfig config = new JedisPoolConfig(); + if (redis.getMaxActive() != null) { + config.setMaxTotal(redis.getMaxActive()); } + if (redis.getMaxIdle() != null) { + config.setMaxIdle(redis.getMaxIdle()); + } + if (redis.getMaxWaitMillis() != null) { + config.setMaxWaitMillis(redis.getMaxWaitMillis()); + } + if (redis.getMinIdle() != null) { + config.setMinIdle(redis.getMinIdle()); + } + config.setTestOnBorrow(true); + config.setTestWhileIdle(true); + + JedisPool pool = new JedisPool(config, redis.getHost(), redis.getPort(), + redis.getTimeout(), redis.getPassword(), redis.getDatabase()); + return pool; + } } diff --git a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/RedisProperties.java b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/RedisProperties.java index 0f0aeca96c..d95e8df984 100644 --- a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/RedisProperties.java +++ b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/RedisProperties.java @@ -5,38 +5,41 @@ import java.io.Serializable; /** - * Redis配置 + * Redis配置. + * + * @author someone */ @Data public class RedisProperties implements Serializable { - - /** - * 主机地址 - */ - private String host = "127.0.0.1"; - - /** - * 端口号 - */ - private int port = 6379; - - /** - * 密码 - */ - private String password; - - /** - * 超时 - */ - private int timeout = 2000; - - /** - * 数据库 - */ - private int database = 0; - - private Integer maxActive; - private Integer maxIdle; - private Integer maxWaitMillis; - private Integer minIdle; + private static final long serialVersionUID = -5924815351660074401L; + + /** + * 主机地址. + */ + private String host = "127.0.0.1"; + + /** + * 端口号. + */ + private int port = 6379; + + /** + * 密码. + */ + private String password; + + /** + * 超时. + */ + private int timeout = 2000; + + /** + * 数据库. + */ + private int database = 0; + + private Integer maxActive; + private Integer maxIdle; + private Integer maxWaitMillis; + private Integer minIdle; } diff --git a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/WxMpProperties.java b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/WxMpProperties.java index 085916cdad..0dbca9e778 100644 --- a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/WxMpProperties.java +++ b/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/WxMpProperties.java @@ -10,7 +10,9 @@ /** - * 微信接入相关配置属性 + * 微信接入相关配置属性. + * + * @author someone */ @Data @ConfigurationProperties(PREFIX) @@ -18,33 +20,34 @@ public class WxMpProperties { public static final String PREFIX = "wx.mp"; /** - * 设置微信公众号的appid + * 设置微信公众号的appid. */ private String appId; /** - * 设置微信公众号的app secret + * 设置微信公众号的app secret. */ private String secret; /** - * 设置微信公众号的token + * 设置微信公众号的token. */ private String token; /** - * 设置微信公众号的EncodingAESKey + * 设置微信公众号的EncodingAESKey. */ private String aesKey; /** - * 存储策略, memory, redis + * 存储策略, memory, redis. */ private ConfigStorage configStorage = new ConfigStorage(); @Data public static class ConfigStorage implements Serializable { + private static final long serialVersionUID = 4815731027000065434L; private StorageType type = memory; @@ -53,6 +56,13 @@ public static class ConfigStorage implements Serializable { } public enum StorageType { - memory, redis + /** + * 内存. + */ + memory, + /** + * redis. + */ + redis } } From 7033b1d5d659cd1ced1257a9bc67b1060c8e91c5 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 10 Aug 2019 17:53:07 +0800 Subject: [PATCH 69/74] =?UTF-8?q?:sparkles:=20#1144=20=E4=BC=81=E4=B8=9A?= =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E6=A8=A1=E5=9D=97=E5=A2=9E=E5=8A=A0=E9=80=9A?= =?UTF-8?q?=E8=BF=87=E6=89=8B=E6=9C=BA=E5=8F=B7=E8=8E=B7=E5=8F=96userid?= =?UTF-8?q?=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/cp/api/WxCpUserService.java | 19 +++++++++++++++++++ .../cp/api/impl/WxCpUserServiceImpl.java | 10 ++++++++++ .../weixin/cp/constant/WxCpApiPathConsts.java | 1 + .../cp/api/impl/WxCpUserServiceImplTest.java | 10 ++++++++++ 4 files changed, 40 insertions(+) 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 544cfb8e9b..8cc77a2d55 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 @@ -137,6 +137,23 @@ public interface WxCpUserService { */ String openid2UserId(String openid) throws WxErrorException; + /** + *
    +   *
    +   * 通过手机号获取其所对应的userid。
    +   *
    +   * 请求方式:POST(HTTPS)
    +   * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/user/getuserid?access_token=ACCESS_TOKEN
    +   *
    +   * 文档地址:https://work.weixin.qq.com/api/doc#90001/90143/91693
    +   * 
    + * + * @param mobile 手机号码。长度为5~32个字节 + * @return userid mobile对应的成员userid + * @throws WxErrorException . + */ + String getUserId(String mobile) throws WxErrorException; + /** * 获取外部联系人详情. *
    @@ -147,6 +164,8 @@ public interface WxCpUserService {
        * 
    * * @param userId 外部联系人的userid + * @return 联系人详情 + * @throws WxErrorException . */ WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException; 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 268ae6bc8e..c75f756635 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 @@ -180,6 +180,16 @@ public String openid2UserId(String openid) throws WxErrorException { return tmpJsonElement.getAsJsonObject().get("userid").getAsString(); } + @Override + public String getUserId(String mobile) throws WxErrorException { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("mobile", mobile); + String url = this.mainService.getWxCpConfigStorage().getApiUrl(GET_USER_ID); + String responseContent = this.mainService.post(url, jsonObject.toString()); + JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + return tmpJsonElement.getAsJsonObject().get("userid").getAsString(); + } + @Override public WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException { String url = this.mainService.getWxCpConfigStorage().getApiUrl(GET_EXTERNAL_CONTACT + userId); diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java index 61c3459f02..6de1a63ac5 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java @@ -101,6 +101,7 @@ public static class User { public static final String BATCH_INVITE = "/cgi-bin/batch/invite"; public static final String USER_CONVERT_TO_OPENID = "/cgi-bin/user/convert_to_openid"; public static final String USER_CONVERT_TO_USERID = "/cgi-bin/user/convert_to_userid"; + public static final String GET_USER_ID = "/cgi-bin/user/getuserid"; public static final String GET_EXTERNAL_CONTACT = "/cgi-bin/crm/get_external_contact?external_userid="; } 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 6b88876fbb..23c86768fd 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 @@ -112,4 +112,14 @@ public void testOpenid2UserId() throws Exception { } + @Test + public void testGetUserId() throws WxErrorException { + String result = this.wxCpService.getUserService().getUserId("xxx"); + System.out.println(result); + assertNotNull(result); + } + + @Test + public void testGetExternalContact() { + } } From 6c77a87833765ea92a98b7a733d9ed4b42bf5ecb Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 10 Aug 2019 18:03:00 +0800 Subject: [PATCH 70/74] =?UTF-8?q?:hammer:=20=E9=87=8D=E6=9E=84=20spring=20?= =?UTF-8?q?boot=20starter=20=E6=A8=A1=E5=9D=97=E7=9B=AE=E5=BD=95=E7=BB=93?= =?UTF-8?q?=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wx-java-mp-spring-boot-starter}/README.md | 2 +- .../wx-java-mp-spring-boot-starter}/pom.xml | 0 .../spring/starter/wxjava/mp/config/WxMpAutoConfiguration.java | 0 .../starter/wxjava/mp/config/WxMpServiceAutoConfiguration.java | 0 .../starter/wxjava/mp/config/WxMpStorageAutoConfiguration.java | 0 .../spring/starter/wxjava/mp/properties/RedisProperties.java | 0 .../spring/starter/wxjava/mp/properties/WxMpProperties.java | 0 .../src/main/resources/META-INF/spring.factories | 0 .../wx-java-pay-spring-boot-starter}/README.md | 2 +- .../wx-java-pay-spring-boot-starter}/pom.xml | 0 .../starter/wxjava/pay/config/WxPayAutoConfiguration.java | 0 .../spring/starter/wxjava/pay/properties/WxPayProperties.java | 0 .../src/main/resources/META-INF/spring.factories | 0 13 files changed, 2 insertions(+), 2 deletions(-) rename {starters/wx-java-mp-starter => spring-boot-starters/wx-java-mp-spring-boot-starter}/README.md (91%) rename {starters/wx-java-mp-starter => spring-boot-starters/wx-java-mp-spring-boot-starter}/pom.xml (100%) rename {starters/wx-java-mp-starter => spring-boot-starters/wx-java-mp-spring-boot-starter}/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpAutoConfiguration.java (100%) rename {starters/wx-java-mp-starter => spring-boot-starters/wx-java-mp-spring-boot-starter}/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpServiceAutoConfiguration.java (100%) rename {starters/wx-java-mp-starter => spring-boot-starters/wx-java-mp-spring-boot-starter}/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpStorageAutoConfiguration.java (100%) rename {starters/wx-java-mp-starter => spring-boot-starters/wx-java-mp-spring-boot-starter}/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/RedisProperties.java (100%) rename {starters/wx-java-mp-starter => spring-boot-starters/wx-java-mp-spring-boot-starter}/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/WxMpProperties.java (100%) rename {starters/wx-java-mp-starter => spring-boot-starters/wx-java-mp-spring-boot-starter}/src/main/resources/META-INF/spring.factories (100%) rename {starters/wx-java-pay-starter => spring-boot-starters/wx-java-pay-spring-boot-starter}/README.md (86%) rename {starters/wx-java-pay-starter => spring-boot-starters/wx-java-pay-spring-boot-starter}/pom.xml (100%) rename {starters/wx-java-pay-starter => spring-boot-starters/wx-java-pay-spring-boot-starter}/src/main/java/com/binarywang/spring/starter/wxjava/pay/config/WxPayAutoConfiguration.java (100%) rename {starters/wx-java-pay-starter => spring-boot-starters/wx-java-pay-spring-boot-starter}/src/main/java/com/binarywang/spring/starter/wxjava/pay/properties/WxPayProperties.java (100%) rename {starters/wx-java-pay-starter => spring-boot-starters/wx-java-pay-spring-boot-starter}/src/main/resources/META-INF/spring.factories (100%) diff --git a/starters/wx-java-mp-starter/README.md b/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md similarity index 91% rename from starters/wx-java-mp-starter/README.md rename to spring-boot-starters/wx-java-mp-spring-boot-starter/README.md index d8e1010322..ec7f343c62 100644 --- a/starters/wx-java-mp-starter/README.md +++ b/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md @@ -4,7 +4,7 @@ ```xml com.github.binarywang - wx-java-mp-starter + wx-java-mp-spring-boot-starter ${version} ``` diff --git a/starters/wx-java-mp-starter/pom.xml b/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml similarity index 100% rename from starters/wx-java-mp-starter/pom.xml rename to spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml diff --git a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpAutoConfiguration.java b/spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpAutoConfiguration.java similarity index 100% rename from starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpAutoConfiguration.java rename to spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpAutoConfiguration.java diff --git a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpServiceAutoConfiguration.java b/spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpServiceAutoConfiguration.java similarity index 100% rename from starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpServiceAutoConfiguration.java rename to spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpServiceAutoConfiguration.java diff --git a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpStorageAutoConfiguration.java b/spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpStorageAutoConfiguration.java similarity index 100% rename from starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpStorageAutoConfiguration.java rename to spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpStorageAutoConfiguration.java diff --git a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/RedisProperties.java b/spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/RedisProperties.java similarity index 100% rename from starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/RedisProperties.java rename to spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/RedisProperties.java diff --git a/starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/WxMpProperties.java b/spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/WxMpProperties.java similarity index 100% rename from starters/wx-java-mp-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/WxMpProperties.java rename to spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/WxMpProperties.java diff --git a/starters/wx-java-mp-starter/src/main/resources/META-INF/spring.factories b/spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/resources/META-INF/spring.factories similarity index 100% rename from starters/wx-java-mp-starter/src/main/resources/META-INF/spring.factories rename to spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/resources/META-INF/spring.factories diff --git a/starters/wx-java-pay-starter/README.md b/spring-boot-starters/wx-java-pay-spring-boot-starter/README.md similarity index 86% rename from starters/wx-java-pay-starter/README.md rename to spring-boot-starters/wx-java-pay-spring-boot-starter/README.md index c987216147..51a363644e 100644 --- a/starters/wx-java-pay-starter/README.md +++ b/spring-boot-starters/wx-java-pay-spring-boot-starter/README.md @@ -3,7 +3,7 @@ ```xml com.github.binarywang - wx-java-pay-starter + wx-java-pay-spring-boot-starter ${version} ``` diff --git a/starters/wx-java-pay-starter/pom.xml b/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml similarity index 100% rename from starters/wx-java-pay-starter/pom.xml rename to spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml diff --git a/starters/wx-java-pay-starter/src/main/java/com/binarywang/spring/starter/wxjava/pay/config/WxPayAutoConfiguration.java b/spring-boot-starters/wx-java-pay-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/pay/config/WxPayAutoConfiguration.java similarity index 100% rename from starters/wx-java-pay-starter/src/main/java/com/binarywang/spring/starter/wxjava/pay/config/WxPayAutoConfiguration.java rename to spring-boot-starters/wx-java-pay-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/pay/config/WxPayAutoConfiguration.java diff --git a/starters/wx-java-pay-starter/src/main/java/com/binarywang/spring/starter/wxjava/pay/properties/WxPayProperties.java b/spring-boot-starters/wx-java-pay-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/pay/properties/WxPayProperties.java similarity index 100% rename from starters/wx-java-pay-starter/src/main/java/com/binarywang/spring/starter/wxjava/pay/properties/WxPayProperties.java rename to spring-boot-starters/wx-java-pay-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/pay/properties/WxPayProperties.java diff --git a/starters/wx-java-pay-starter/src/main/resources/META-INF/spring.factories b/spring-boot-starters/wx-java-pay-spring-boot-starter/src/main/resources/META-INF/spring.factories similarity index 100% rename from starters/wx-java-pay-starter/src/main/resources/META-INF/spring.factories rename to spring-boot-starters/wx-java-pay-spring-boot-starter/src/main/resources/META-INF/spring.factories From 23ab47229308ffbb67ebe9554816dceed68b3a65 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 10 Aug 2019 18:22:50 +0800 Subject: [PATCH 71/74] =?UTF-8?q?:hammer:=20=E9=87=8D=E6=9E=84=20spring=20?= =?UTF-8?q?boot=20starter=20=E6=A8=A1=E5=9D=97=E7=9B=AE=E5=BD=95=E7=BB=93?= =?UTF-8?q?=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml | 4 ++-- spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml index 0350280dea..76b8fbc82b 100644 --- a/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml +++ b/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml @@ -10,9 +10,9 @@ ../../ - wx-java-mp-starter + wx-java-mp-spring-boot-starter WxJava - Spring Boot Starter for MP - 微信公众号开发的Spring Boot Starter + 微信公众号开发的 Spring Boot Starter 2.1.4.RELEASE diff --git a/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml index 0ce75995ba..bc233fa488 100644 --- a/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml +++ b/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml @@ -10,9 +10,9 @@ 4.0.0 - wx-java-pay-starter + wx-java-pay-spring-boot-starter WxJava - Spring Boot Starter for WxPay - 微信支付开发的Spring Boot Starter + 微信支付开发的 Spring Boot Starter 2.1.4.RELEASE From 3c099f8d8dcda159346e926ee7d32a4e946b0d05 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 10 Aug 2019 18:43:05 +0800 Subject: [PATCH 72/74] =?UTF-8?q?:sparkles:=20#1082=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E5=B0=8F=E7=A8=8B=E5=BA=8F=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E7=9A=84spring-boot-starter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 5 +- .../README.md | 26 +++++++ .../pom.xml | 68 +++++++++++++++++++ .../miniapp/config/WxMaAutoConfiguration.java | 50 ++++++++++++++ .../miniapp/properties/WxMaProperties.java | 39 +++++++++++ .../main/resources/META-INF/spring.factories | 1 + .../wx-java-pay-spring-boot-starter/README.md | 6 +- 7 files changed, 190 insertions(+), 5 deletions(-) create mode 100644 spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md create mode 100644 spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml create mode 100644 spring-boot-starters/wx-java-miniapp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/config/WxMaAutoConfiguration.java create mode 100644 spring-boot-starters/wx-java-miniapp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/properties/WxMaProperties.java create mode 100644 spring-boot-starters/wx-java-miniapp-spring-boot-starter/src/main/resources/META-INF/spring.factories diff --git a/pom.xml b/pom.xml index 35b0be5125..b310bd9c91 100644 --- a/pom.xml +++ b/pom.xml @@ -105,8 +105,9 @@ weixin-java-pay weixin-java-miniapp weixin-java-open - starters/wx-java-pay-starter - starters/wx-java-mp-starter + spring-boot-starters/wx-java-pay-spring-boot-starter + spring-boot-starters/wx-java-mp-spring-boot-starter + spring-boot-starters/wx-java-miniapp-spring-boot-starter diff --git a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md new file mode 100644 index 0000000000..fe75ef4e3e --- /dev/null +++ b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md @@ -0,0 +1,26 @@ +# 使用说明 +1. 在自己的Spring Boot项目里,引入maven依赖 +```xml + + com.github.binarywang + wx-java-miniapp-spring-boot-starter + ${version} + + ``` +2. 添加配置(application.yml) +```yml +wx: + miniapp: + appid: 111 + secret: 111 + token: 111 + aesKey: 111 + msgDataFormat: JSON +``` + + + + + + + diff --git a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml new file mode 100644 index 0000000000..6ee7329082 --- /dev/null +++ b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml @@ -0,0 +1,68 @@ + + + + wx-java + com.github.binarywang + 3.4.9.B + ../../ + + 4.0.0 + + wx-java-miniapp-spring-boot-starter + WxJava - Spring Boot Starter for MiniApp + 微信小程序开发的 Spring Boot Starter + + + 2.1.4.RELEASE + + + + + org.springframework.boot + spring-boot-autoconfigure + ${spring.boot.version} + + + org.springframework.boot + spring-boot-configuration-processor + ${spring.boot.version} + true + + + org.projectlombok + lombok + provided + + + com.github.binarywang + weixin-java-miniapp + ${project.version} + + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + + attach-sources + + jar-no-fork + + + + + + + + diff --git a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/config/WxMaAutoConfiguration.java b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/config/WxMaAutoConfiguration.java new file mode 100644 index 0000000000..109b398d13 --- /dev/null +++ b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/config/WxMaAutoConfiguration.java @@ -0,0 +1,50 @@ +package com.binarywang.spring.starter.wxjava.miniapp.config; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl; +import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties; +import lombok.AllArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 自动配置. + * + * @author Binary Wang + * @date 2019-08-10 + */ +@AllArgsConstructor +@Configuration +@ConditionalOnClass(WxMaService.class) +@EnableConfigurationProperties(WxMaProperties.class) +@ConditionalOnProperty(prefix = "wx.miniapp", value = "enabled", matchIfMissing = true) +public class WxMaAutoConfiguration { + private WxMaProperties properties; + + /** + * 小程序service. + * + * @return 小程序service + */ + @Bean + @ConditionalOnMissingBean(WxMaService.class) + public WxMaService service() { + WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl(); + config.setAppid(StringUtils.trimToNull(this.properties.getAppid())); + config.setSecret(StringUtils.trimToNull(this.properties.getSecret())); + config.setToken(StringUtils.trimToNull(this.properties.getToken())); + config.setAesKey(StringUtils.trimToNull(this.properties.getAesKey())); + config.setMsgDataFormat(StringUtils.trimToNull(this.properties.getMsgDataFormat())); + + final WxMaServiceImpl service = new WxMaServiceImpl(); + service.setWxMaConfig(config); + return service; + } +} diff --git a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/properties/WxMaProperties.java b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/properties/WxMaProperties.java new file mode 100644 index 0000000000..6477e61fa2 --- /dev/null +++ b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/properties/WxMaProperties.java @@ -0,0 +1,39 @@ +package com.binarywang.spring.starter.wxjava.miniapp.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * 属性配置类. + * + * @author Binary Wang + * @date 2019-08-10 + */ +@Data +@ConfigurationProperties(prefix = "wx.miniapp") +public class WxMaProperties { + /** + * 设置微信小程序的appid. + */ + private String appid; + + /** + * 设置微信小程序的Secret. + */ + private String secret; + + /** + * 设置微信小程序消息服务器配置的token. + */ + private String token; + + /** + * 设置微信小程序消息服务器配置的EncodingAESKey. + */ + private String aesKey; + + /** + * 消息格式,XML或者JSON. + */ + private String msgDataFormat; +} diff --git a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/src/main/resources/META-INF/spring.factories b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000000..4bb1c3d604 --- /dev/null +++ b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.binarywang.spring.starter.wxjava.miniapp.config.WxMaAutoConfiguration diff --git a/spring-boot-starters/wx-java-pay-spring-boot-starter/README.md b/spring-boot-starters/wx-java-pay-spring-boot-starter/README.md index 51a363644e..a4d91fade0 100644 --- a/spring-boot-starters/wx-java-pay-spring-boot-starter/README.md +++ b/spring-boot-starters/wx-java-pay-spring-boot-starter/README.md @@ -11,9 +11,9 @@ ```yml wx: pay: - appId: wx5b69c56ac01ed858 - mchId: 1462547202 - mchKey: OGL9fvig9y2HrXrQ86tM4jTwyv4ja6G5 + appId: + mchId: + mchKey: subAppId: subMchId: keyPath: From 64d4bc58b3056727033c47b55aa16d0905466cce Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 10 Aug 2019 18:49:10 +0800 Subject: [PATCH 73/74] =?UTF-8?q?:heavy=5Fminus=5Fsign:=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E6=97=A0=E7=94=A8=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index c5f3f6b9c7..0000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "java.configuration.updateBuildConfiguration": "interactive" -} \ No newline at end of file From 3bf1bb928e48bfaf59edda33b31ce2f63f059931 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 10 Aug 2019 19:14:14 +0800 Subject: [PATCH 74/74] =?UTF-8?q?:bookmark:=20=E5=8F=91=E5=B8=833.5.0?= =?UTF-8?q?=E6=AD=A3=E5=BC=8F=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- .../wx-java-miniapp-spring-boot-starter/pom.xml | 2 +- spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml | 2 +- spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml | 2 +- weixin-java-common/pom.xml | 2 +- weixin-java-cp/pom.xml | 2 +- weixin-java-miniapp/pom.xml | 2 +- weixin-java-mp/pom.xml | 2 +- weixin-java-open/pom.xml | 2 +- weixin-java-pay/pom.xml | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pom.xml b/pom.xml index b310bd9c91..d137dac03c 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 com.github.binarywang wx-java - 3.4.9.B + 3.5.0 pom WxJava - Weixin/Wechat Java SDK 微信开发Java SDK diff --git a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml index 6ee7329082..1c5b89d109 100644 --- a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml +++ b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ wx-java com.github.binarywang - 3.4.9.B + 3.5.0 ../../ 4.0.0 diff --git a/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml index 76b8fbc82b..366d2532f6 100644 --- a/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml +++ b/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml @@ -6,7 +6,7 @@ com.github.binarywang wx-java - 3.4.9.B + 3.5.0 ../../ diff --git a/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml index bc233fa488..3e72689936 100644 --- a/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml +++ b/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ wx-java com.github.binarywang - 3.4.9.B + 3.5.0 ../../ 4.0.0 diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index b3461b93ee..9795b05dc6 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -6,7 +6,7 @@ com.github.binarywang wx-java - 3.4.9.B + 3.5.0 weixin-java-common diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index 62638cf3f7..10269ebdc2 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.4.9.B + 3.5.0 weixin-java-cp diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml index d46ec3e9e2..fb7cf4f619 100644 --- a/weixin-java-miniapp/pom.xml +++ b/weixin-java-miniapp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.4.9.B + 3.5.0 weixin-java-miniapp diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index 763e8fea05..8792a55e1c 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.4.9.B + 3.5.0 weixin-java-mp diff --git a/weixin-java-open/pom.xml b/weixin-java-open/pom.xml index a0a3067eee..7a2c2457e4 100644 --- a/weixin-java-open/pom.xml +++ b/weixin-java-open/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.4.9.B + 3.5.0 weixin-java-open diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index 00b97de20d..03188c8c03 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -5,7 +5,7 @@ com.github.binarywang wx-java - 3.4.9.B + 3.5.0 4.0.0