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 index 2b3a17b87..8c0ea9685 100644 --- 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 @@ -1,5 +1,6 @@ package me.chanjar.weixin.cp.api; +import lombok.NonNull; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.cp.bean.*; @@ -15,6 +16,83 @@ import java.util.List; * @author JoeCao */ public interface WxCpExternalContactService { + + /** + * 配置客户联系「联系我」方式 + *
+ * 企业可以在管理后台-客户联系中配置成员的「联系我」的二维码或者小程序按钮,客户通过扫描二维码或点击小程序上的按钮,即可获取成员联系方式,主动联系到成员。 + * 企业可通过此接口为具有客户联系功能的成员生成专属的「联系我」二维码或者「联系我」按钮。 + * 如果配置的是「联系我」按钮,需要开发者的小程序接入小程序插件。 + * + * 注意: + * 通过API添加的「联系我」不会在管理端进行展示,每个企业可通过API最多配置50万个「联系我」。 + * 用户需要妥善存储返回的config_id,config_id丢失可能导致用户无法编辑或删除「联系我」。 + * 临时会话模式不占用「联系我」数量,但每日最多添加10万个,并且仅支持单人。 + * 临时会话模式的二维码,添加好友完成后该二维码即刻失效。 + *+ * + * @param info 客户联系「联系我」方式 + * @return + * @throws WxErrorException + */ + WxCpContactWayResult addContactWay(@NonNull WxCpContactWayInfo info) throws WxErrorException; + + /** + * 获取企业已配置的「联系我」方式 + * + *
+ * 批量获取企业配置的「联系我」二维码和「联系我」小程序按钮。 + *+ * + * @param configId 联系方式的配置id,必填 + * @return + * @throws WxErrorException + */ + WxCpContactWayInfo getContactWay(@NonNull String configId) throws WxErrorException; + + /** + * 更新企业已配置的「联系我」方式 + * + *
+ * 更新企业配置的「联系我」二维码和「联系我」小程序按钮中的信息,如使用人员和备注等。 + *+ * + * @param info 客户联系「联系我」方式 + * @return + * @throws WxErrorException + */ + WxCpBaseResp updateContactWay(@NonNull WxCpContactWayInfo info) throws WxErrorException; + + /** + * 删除企业已配置的「联系我」方式 + * + *
+ * 删除一个已配置的「联系我」二维码或者「联系我」小程序按钮。 + *+ * + * @param configId 企业联系方式的配置id,必填 + * @return + * @throws WxErrorException + */ + WxCpBaseResp deleteContactWay(@NonNull String configId) throws WxErrorException; + + /** + * 结束临时会话 + * + *
+ * 将指定的企业成员和客户之前的临时会话断开,断开前会自动下发已配置的结束语。 + * + * 注意:请保证传入的企业成员和客户之间有仍然有效的临时会话, 通过其他方式的添加外部联系人无法通过此接口关闭会话。 + *+ * + * @param userId + * @param externalUserId + * @return + * @throws WxErrorException + */ + WxCpBaseResp closeTempChat(@NonNull String userId, @NonNull String externalUserId) throws WxErrorException; + + /** * 获取外部联系人详情. *
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
index 982c11550..371015b41 100644
--- 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
@@ -2,6 +2,7 @@ package me.chanjar.weixin.cp.api.impl;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
+import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.common.error.WxCpErrorMsgEnum;
import me.chanjar.weixin.common.error.WxErrorException;
@@ -9,6 +10,7 @@ import me.chanjar.weixin.cp.api.WxCpExternalContactService;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.*;
import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
import java.util.Collections;
import java.util.Date;
@@ -23,6 +25,70 @@ import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.ExternalContact.*;
public class WxCpExternalContactServiceImpl implements WxCpExternalContactService {
private final WxCpService mainService;
+ @Override
+ public WxCpContactWayResult addContactWay(@NonNull WxCpContactWayInfo info) throws WxErrorException {
+
+ if (info.getUsers() != null && info.getUsers().size() > 100) {
+ throw new RuntimeException("「联系我」使用人数默认限制不超过100人(包括部门展开后的人数)");
+ }
+
+ final String url = this.mainService.getWxCpConfigStorage().getApiUrl(ADD_CONTACT_WAY);
+ String responseContent = this.mainService.post(url, info.toJson());
+
+ return WxCpContactWayResult.fromJson(responseContent);
+ }
+
+ @Override
+ public WxCpContactWayInfo getContactWay(@NonNull String configId) throws WxErrorException {
+ JsonObject json = new JsonObject();
+ json.addProperty("config_id", configId);
+
+ final String url = this.mainService.getWxCpConfigStorage().getApiUrl(GET_CONTACT_WAY);
+ String responseContent = this.mainService.post(url, json.toString());
+
+ return WxCpContactWayInfo.fromJson(responseContent);
+ }
+
+ @Override
+ public WxCpBaseResp updateContactWay(@NonNull WxCpContactWayInfo info) throws WxErrorException {
+ if (StringUtils.isBlank(info.getConfigId())) {
+ throw new RuntimeException("更新「联系我」方式需要指定configId");
+ }
+ if (info.getUsers() != null && info.getUsers().size() > 100) {
+ throw new RuntimeException("「联系我」使用人数默认限制不超过100人(包括部门展开后的人数)");
+ }
+
+ final String url = this.mainService.getWxCpConfigStorage().getApiUrl(UPDATE_CONTACT_WAY);
+ String responseContent = this.mainService.post(url, info.toJson());
+
+ return WxCpBaseResp.fromJson(responseContent);
+ }
+
+ @Override
+ public WxCpBaseResp deleteContactWay(@NonNull String configId) throws WxErrorException {
+ JsonObject json = new JsonObject();
+ json.addProperty("config_id",configId);
+
+ final String url = this.mainService.getWxCpConfigStorage().getApiUrl(DEL_CONTACT_WAY);
+ String responseContent = this.mainService.post(url, json.toString());
+
+ return WxCpBaseResp.fromJson(responseContent);
+ }
+
+ @Override
+ public WxCpBaseResp closeTempChat(@NonNull String userId, @NonNull String externalUserId) throws WxErrorException {
+
+ JsonObject json = new JsonObject();
+ json.addProperty("userid",userId);
+ json.addProperty("external_userid",externalUserId);
+
+
+ final String url = this.mainService.getWxCpConfigStorage().getApiUrl(CLOSE_TEMP_CHAT);
+ String responseContent = this.mainService.post(url, json.toString());
+
+ return WxCpBaseResp.fromJson(responseContent);
+ }
+
@Override
public WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException {
final String url = this.mainService.getWxCpConfigStorage().getApiUrl(GET_EXTERNAL_CONTACT + userId);
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpContactWayInfo.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpContactWayInfo.java
new file mode 100644
index 000000000..3f62e4f0e
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpContactWayInfo.java
@@ -0,0 +1,198 @@
+package me.chanjar.weixin.cp.bean;
+
+import com.google.gson.annotations.JsonAdapter;
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.cp.util.json.WxCpConclusionAdapter;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+import java.util.List;
+
+/**
+ * 「联系我」方式 对象
+ *
+ * @author element
+ */
+@Data
+@NoArgsConstructor
+public class WxCpContactWayInfo {
+
+ /**
+ * 联系方式的配置id
+ */
+ @SerializedName("config_id")
+ private String configId;
+
+ /**
+ *
+ * 必填
+ * 联系方式类型,1-单人, 2-多人
+ *
+ */
+ private TYPE type;
+
+ /**
+ *
+ * 必填
+ * 场景,1-在小程序中联系,2-通过二维码联系
+ *
+ */
+ private SCENE scene;
+
+ /**
+ *
+ * 非必填
+ * 在小程序中联系时使用的控件样式
+ * 单人样式(type=1)时可选1,2,3
+ * 多人样式(type=2)时可选1,2
+ *
+ */
+ private Integer style;
+
+ /**
+ *
+ * 非必填
+ * 联系方式的备注信息,用于助记,不超过30个字符
+ *
+ */
+ private String remark;
+
+ /**
+ *
+ * 非必填
+ * 外部客户添加时是否无需验证,默认为true
+ *
+ */
+ @SerializedName("skip_verify")
+ private Boolean skipVerify = Boolean.TRUE;
+
+ /**
+ *
+ * 非必填
+ * 企业自定义的state参数,用于区分不同的添加渠道,在调用“获取外部联系人详情(WxCpExternalContactService.getContactDetail)” 时会返回该参数值,不超过30个字符
+ *
+ */
+ private String state;
+
+ /**
+ *
+ * 使用该联系方式的用户userID列表,在type为1时为必填,且只能有一个
+ *
+ */
+ @SerializedName("user")
+ private List users;
+
+
+ /**
+ *
+ * 非必填
+ * 使用该联系方式的部门id列表,只在type为2时有效
+ *
+ */
+ @SerializedName("party")
+ private List partys;
+
+ /**
+ *
+ * 非必填
+ * 是否临时会话模式,true表示使用临时会话模式,默认为false
+ *
+ */
+ @SerializedName("is_temp")
+ private Boolean isTemp = Boolean.FALSE;
+
+ /**
+ *
+ * 非必填
+ * 临时会话二维码有效期,以秒为单位。该参数仅在is_temp为true时有效,默认7天
+ *
+ */
+ @SerializedName("expires_in")
+ private Integer expiresIn;
+
+ /**
+ *
+ * 非必填
+ * 临时会话有效期,以秒为单位。该参数仅在is_temp为true时有效,默认为添加好友后24小时
+ *
+ */
+ @SerializedName("chat_expires_in")
+ private Integer chatExpiresIn;
+
+ /**
+ *
+ * 非必填
+ * 可进行临时会话的客户unionid,该参数仅在is_temp为true时有效,如不指定则不进行限制
+ *
+ */
+ @SerializedName("unionid")
+ private String unionId;
+
+ /**
+ *
+ * 非必填
+ * 结束语,会话结束时自动发送给客户,可参考“结束语定义”,仅在is_temp为true时有效
+ *
+ */
+ private Conclusion conclusions;
+
+ public static WxCpContactWayInfo fromJson(String json) {
+ return WxCpGsonBuilder.create().fromJson(json, WxCpContactWayInfo.class);
+ }
+
+ public String toJson() {
+ return WxCpGsonBuilder.create().toJson(this);
+ }
+
+ /**
+ * 结束语定义
+ */
+ @Data
+ @JsonAdapter(WxCpConclusionAdapter.class)
+ public static class Conclusion {
+ private String textContent;
+ private String imgMediaId;
+ private String imgPicUrl;
+ private String linkTitle;
+ private String linkPicUrl;
+ private String linkDesc;
+ private String linkUrl;
+ private String miniProgramTitle;
+ private String miniProgramPicMediaId;
+ private String miniProgramAppId;
+ private String miniProgramPage;
+ }
+
+ public enum TYPE {
+ /**
+ * 单人
+ */
+ @SerializedName("1")
+ SIGLE,
+
+ /**
+ * 多人
+ */
+ @SerializedName("2")
+ MULTI;
+
+ }
+
+ public enum SCENE {
+
+ /**
+ * 在小程序中联系
+ */
+ @SerializedName("1")
+ MINIPROGRAM,
+
+ /**
+ * 通过二维码联系
+ */
+ @SerializedName("2")
+ QRCODE;
+
+ }
+
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpContactWayResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpContactWayResult.java
new file mode 100644
index 000000000..89d58454d
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpContactWayResult.java
@@ -0,0 +1,18 @@
+package me.chanjar.weixin.cp.bean;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+/**
+ * 「联系我」方式 处理结果
+ */
+@Data
+public class WxCpContactWayResult extends WxCpBaseResp {
+ @SerializedName("config_id")
+ private String configId;
+
+ public static WxCpContactWayResult fromJson(String json) {
+ return WxCpGsonBuilder.create().fromJson(json, WxCpContactWayResult.class);
+ }
+}
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 24debae39..72ababe77 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
@@ -117,6 +117,11 @@ public final class WxCpApiPathConsts {
@Deprecated
public static final String GET_EXTERNAL_CONTACT = "/cgi-bin/crm/get_external_contact?external_userid=";
+ public static final String ADD_CONTACT_WAY = "/cgi-bin/externalcontact/add_contact_way";
+ public static final String GET_CONTACT_WAY = "/cgi-bin/externalcontact/get_contact_way";
+ public static final String UPDATE_CONTACT_WAY = "/cgi-bin/externalcontact/update_contact_way";
+ public static final String DEL_CONTACT_WAY = "/cgi-bin/externalcontact/del_contact_way";
+ public static final String CLOSE_TEMP_CHAT = "/cgi-bin/externalcontact/close_temp_chat";
public static final String GET_FOLLOW_USER_LIST = "/cgi-bin/externalcontact/get_follow_user_list";
public static final String GET_CONTACT_DETAIL = "/cgi-bin/externalcontact/get?external_userid=";
public static final String LIST_EXTERNAL_CONTACT = "/cgi-bin/externalcontact/list?userid=";
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpConclusionAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpConclusionAdapter.java
new file mode 100644
index 000000000..1a9aab8bf
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpConclusionAdapter.java
@@ -0,0 +1,123 @@
+package me.chanjar.weixin.cp.util.json;
+
+import com.google.gson.*;
+import me.chanjar.weixin.cp.bean.WxCpContactWayInfo;
+import org.apache.commons.lang3.StringUtils;
+
+import java.lang.reflect.Type;
+
+/**
+ * 结束语序列化转换器
+ *
+ * @author element
+ */
+public class WxCpConclusionAdapter implements JsonSerializer, JsonDeserializer {
+ @Override
+ public WxCpContactWayInfo.Conclusion deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
+ JsonObject jsonObject = json.getAsJsonObject();
+
+ WxCpContactWayInfo.Conclusion conclusion = new WxCpContactWayInfo.Conclusion();
+
+ if (jsonObject.get("text") != null) {
+ JsonObject jsonText = jsonObject.get("text").getAsJsonObject();
+
+ if (jsonText.get("content") != null) {
+ conclusion.setTextContent(jsonText.get("content").getAsString());
+ }
+ }
+
+ if (jsonObject.get("image") != null) {
+ JsonObject jsonImage = jsonObject.get("image").getAsJsonObject();
+
+ if (jsonImage.get("media_id") != null) {
+ conclusion.setImgMediaId(jsonImage.get("media_id").getAsString());
+ }
+
+ if (jsonImage.get("pic_url") != null) {
+ conclusion.setImgPicUrl(jsonImage.get("pic_url").getAsString());
+ }
+ }
+
+ if (jsonObject.get("link") != null) {
+ JsonObject jsonLink = jsonObject.get("link").getAsJsonObject();
+
+ if (jsonLink.get("title") != null) {
+ conclusion.setLinkTitle(jsonLink.get("title").getAsString());
+ }
+ if (jsonLink.get("picurl") != null) {
+ conclusion.setLinkPicUrl(jsonLink.get("picurl").getAsString());
+ }
+ if (jsonLink.get("desc") != null) {
+ conclusion.setLinkDesc(jsonLink.get("desc").getAsString());
+ }
+ if (jsonLink.get("url") != null) {
+ conclusion.setLinkUrl(jsonLink.get("url").getAsString());
+ }
+ }
+
+ if (jsonObject.get("miniprogram") != null) {
+
+ JsonObject jsonMiniProgram = jsonObject.get("miniprogram").getAsJsonObject();
+ if (jsonMiniProgram.get("title") != null) {
+ conclusion.setMiniProgramTitle(jsonMiniProgram.get("title").getAsString());
+ }
+ if (jsonMiniProgram.get("pic_media_id") != null) {
+ conclusion.setMiniProgramPicMediaId(jsonMiniProgram.get("pic_media_id").getAsString());
+ }
+ if (jsonMiniProgram.get("appid") != null) {
+ conclusion.setMiniProgramAppId(jsonMiniProgram.get("appid").getAsString());
+ }
+ if (jsonMiniProgram.get("page") != null) {
+ conclusion.setMiniProgramPage(jsonMiniProgram.get("page").getAsString());
+ }
+
+ }
+
+ return conclusion;
+ }
+
+ @Override
+ public JsonElement serialize(WxCpContactWayInfo.Conclusion src, Type typeOfSrc, JsonSerializationContext context) {
+ JsonObject json = new JsonObject();
+ if (StringUtils.isNotBlank(src.getTextContent())) {
+ JsonObject jsonText = new JsonObject();
+ jsonText.addProperty("content", src.getTextContent());
+ json.add("text", jsonText);
+ }
+
+ if (StringUtils.isNotBlank(src.getImgMediaId()) || StringUtils.isNotBlank(src.getImgPicUrl())) {
+ JsonObject jsonImg = new JsonObject();
+ jsonImg.addProperty("media_id", src.getImgMediaId());
+ jsonImg.addProperty("pic_url", src.getImgPicUrl());
+ json.add("image", jsonImg);
+ }
+
+ if (StringUtils.isNotBlank(src.getLinkTitle())
+ || StringUtils.isNotBlank(src.getLinkPicUrl())
+ || StringUtils.isNotBlank(src.getLinkDesc())
+ || StringUtils.isNotBlank(src.getLinkUrl())
+ ) {
+ JsonObject jsonLink = new JsonObject();
+ jsonLink.addProperty("title", src.getLinkTitle());
+ jsonLink.addProperty("picurl", src.getLinkPicUrl());
+ jsonLink.addProperty("desc", src.getLinkDesc());
+ jsonLink.addProperty("url", src.getLinkUrl());
+ json.add("link", jsonLink);
+ }
+
+ if (StringUtils.isNotBlank(src.getMiniProgramTitle())
+ || StringUtils.isNotBlank(src.getMiniProgramPicMediaId())
+ || StringUtils.isNotBlank(src.getMiniProgramAppId())
+ || StringUtils.isNotBlank(src.getMiniProgramPage())
+ ) {
+ JsonObject jsonMiniProgram = new JsonObject();
+ jsonMiniProgram.addProperty("title", src.getMiniProgramTitle());
+ jsonMiniProgram.addProperty("pic_media_id", src.getMiniProgramPicMediaId());
+ jsonMiniProgram.addProperty("appid", src.getMiniProgramAppId());
+ jsonMiniProgram.addProperty("page", src.getMiniProgramPage());
+ json.add("miniprogram", jsonMiniProgram);
+ }
+
+ return json;
+ }
+}
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
index 309b14bc2..da04bc6c0 100644
--- 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
@@ -1,13 +1,18 @@
package me.chanjar.weixin.cp.api.impl;
+import com.google.common.collect.Lists;
import com.google.inject.Inject;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.ApiTestModule;
import me.chanjar.weixin.cp.api.WxCpService;
+import me.chanjar.weixin.cp.bean.WxCpBaseResp;
+import me.chanjar.weixin.cp.bean.WxCpContactWayInfo;
import me.chanjar.weixin.cp.bean.WxCpUserExternalContactInfo;
+import org.apache.commons.lang3.time.DateFormatUtils;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
+import java.util.Date;
import java.util.List;
import static org.testng.Assert.assertNotNull;
@@ -28,6 +33,55 @@ public class WxCpExternalContactServiceImplTest {
assertNotNull(result);
}
+ @Test
+ public void testAddContactWay() throws WxErrorException {
+
+ final String concatUserId = "符合要求的userId";
+
+ WxCpContactWayInfo info = new WxCpContactWayInfo();
+ info.setType(WxCpContactWayInfo.TYPE.SIGLE);
+ info.setScene(WxCpContactWayInfo.SCENE.MINIPROGRAM);
+ info.setUsers(Lists.newArrayList(concatUserId));
+ info.setRemark("CreateDate:" + DateFormatUtils.ISO_8601_EXTENDED_DATETIME_FORMAT.format(new Date()));
+ this.wxCpService.getExternalContactService().addContactWay(info);
+ }
+
+ @Test
+ public void testGetContactWay() throws WxErrorException {
+ final String configId = "2d7a68c657663afbd1d90db19a4b5ee9";
+ WxCpContactWayInfo contactWayInfo = this.wxCpService.getExternalContactService().getContactWay(configId);
+ System.out.println(contactWayInfo);
+ assertNotNull(contactWayInfo);
+ }
+
+ @Test
+ public void testUpdateContactWay() throws WxErrorException {
+ final String configId = "2d7a68c657663afbd1d90db19a4b5ee9";
+ final String concatUserId = "符合要求的userId";
+ WxCpContactWayInfo info = new WxCpContactWayInfo();
+ info.setConfigId(configId);
+ info.setUsers(Lists.newArrayList(concatUserId));
+ info.setRemark("CreateDate:" + DateFormatUtils.ISO_8601_EXTENDED_DATETIME_FORMAT.format(new Date()));
+ WxCpBaseResp resp = this.wxCpService.getExternalContactService().updateContactWay(info);
+ System.out.println(resp);
+ assertNotNull(resp);
+ }
+
+ @Test
+ public void testDelContactWay() throws WxErrorException {
+ final String configId = "2d7a68c657663afbd1d90db19a4b5ee9";
+ WxCpBaseResp resp = this.wxCpService.getExternalContactService().deleteContactWay(configId);
+ System.out.println(resp);
+ assertNotNull(resp);
+ }
+
+ @Test
+ public void testCloseTempChat() throws WxErrorException {
+ final String externalUserId = "externalUserId";
+ WxCpBaseResp resp = this.wxCpService.getExternalContactService().closeTempChat(userId, externalUserId);
+ System.out.println(resp);
+ }
+
@Test
public void testListExternalContacts() throws WxErrorException {
String userId = this.configStorage.getUserId();
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 4d1c2b136..4b496b30d 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
@@ -208,6 +208,13 @@ public interface WxOpenConfigStorage {
*/
void setAuthorizerRefreshToken(String appId, String authorizerRefreshToken);
+ /**
+ * setAuthorizerRefreshToken(String appId, String authorizerRefreshToken) 方法重载方法
+ * @param appId the app id
+ * @param authorizerRefreshToken the authorizer refresh token
+ */
+ void updateAuthorizerRefreshToken(String appId, String authorizerRefreshToken);
+
/**
* Gets authorizer access token.
*
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 fe2a782e4..80961921f 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
@@ -311,7 +311,7 @@ public class WxOpenComponentServiceImpl implements WxOpenComponentService {
authorizationInfo.getAuthorizerAccessToken(), authorizationInfo.getExpiresIn());
}
if (authorizationInfo.getAuthorizerRefreshToken() != null) {
- getWxOpenConfigStorage().setAuthorizerRefreshToken(authorizationInfo.getAuthorizerAppid(), authorizationInfo.getAuthorizerRefreshToken());
+ getWxOpenConfigStorage().updateAuthorizerRefreshToken(authorizationInfo.getAuthorizerAppid(), authorizationInfo.getAuthorizerRefreshToken());
}
return queryAuth;
}
@@ -340,7 +340,7 @@ public class WxOpenComponentServiceImpl implements WxOpenComponentService {
String authorizerAppid = data.get("authorizer_appid");
String refreshToken = data.get("refresh_token");
if (authorizerAppid != null && refreshToken != null) {
- this.getWxOpenConfigStorage().setAuthorizerRefreshToken(authorizerAppid, refreshToken);
+ this.getWxOpenConfigStorage().updateAuthorizerRefreshToken(authorizerAppid, refreshToken);
}
}
}
@@ -391,6 +391,7 @@ public class WxOpenComponentServiceImpl implements WxOpenComponentService {
WxOpenAuthorizerAccessToken wxOpenAuthorizerAccessToken = WxOpenAuthorizerAccessToken.fromJson(responseContent);
config.updateAuthorizerAccessToken(appId, wxOpenAuthorizerAccessToken);
+ config.updateAuthorizerRefreshToken(appId,wxOpenAuthorizerAccessToken.getAuthorizerRefreshToken());
return config.getAuthorizerAccessToken(appId);
} catch (InterruptedException e) {
throw new RuntimeException(e);
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 723ec3806..a4859ba18 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
@@ -142,7 +142,7 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage {
map.put(key, token);
}
token.token = tokenString;
- if (expiresInSeconds != null) {
+ if (expiresInSeconds != null && expiresInSeconds != -1) {
token.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
}
}
@@ -157,6 +157,11 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage {
updateToken(authorizerRefreshTokens, appId, authorizerRefreshToken, null);
}
+ @Override
+ public void updateAuthorizerRefreshToken(String appId, String authorizerRefreshToken) {
+ this.setAuthorizerRefreshToken(appId, authorizerRefreshToken);
+ }
+
@Override
public String getAuthorizerAccessToken(String appId) {
return getTokenString(authorizerAccessTokens, appId);
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/WxOpenAuthorizerAccessToken.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/WxOpenAuthorizerAccessToken.java
index 9b86412bb..9a558ab77 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/WxOpenAuthorizerAccessToken.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/WxOpenAuthorizerAccessToken.java
@@ -1,5 +1,6 @@
package me.chanjar.weixin.open.bean;
+import lombok.Data;
import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder;
import java.io.Serializable;
@@ -7,30 +8,17 @@ import java.io.Serializable;
/**
* @author 007
*/
+@Data
public class WxOpenAuthorizerAccessToken implements Serializable {
private static final long serialVersionUID = -4069745419280727420L;
private String authorizerAccessToken;
+ private String authorizerRefreshToken;
+
private int expiresIn = -1;
public static WxOpenAuthorizerAccessToken fromJson(String json) {
return WxOpenGsonBuilder.create().fromJson(json, WxOpenAuthorizerAccessToken.class);
}
-
- public String getAuthorizerAccessToken() {
- return authorizerAccessToken;
- }
-
- public void setAuthorizerAccessToken(String authorizerAccessToken) {
- this.authorizerAccessToken = authorizerAccessToken;
- }
-
- public int getExpiresIn() {
- return expiresIn;
- }
-
- public void setExpiresIn(int expiresIn) {
- this.expiresIn = expiresIn;
- }
}
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenAuthorizerAccessTokenGsonAdapter.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenAuthorizerAccessTokenGsonAdapter.java
index 82a04b9ba..6932d2573 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenAuthorizerAccessTokenGsonAdapter.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenAuthorizerAccessTokenGsonAdapter.java
@@ -15,6 +15,7 @@ public class WxOpenAuthorizerAccessTokenGsonAdapter implements JsonDeserializer<
WxOpenAuthorizerAccessToken authorizerAccessToken = new WxOpenAuthorizerAccessToken();
JsonObject jsonObject = jsonElement.getAsJsonObject();
authorizerAccessToken.setAuthorizerAccessToken(GsonHelper.getString(jsonObject, "authorizer_access_token"));
+ authorizerAccessToken.setAuthorizerRefreshToken(GsonHelper.getString(jsonObject, "authorizer_refresh_token"));
authorizerAccessToken.setExpiresIn(GsonHelper.getPrimitiveInteger(jsonObject, "expires_in"));
return authorizerAccessToken;
}