Skip to content

Commit 0758049

Browse files
authored
🆕 #1474 企业微信新增客户联系「联系我」管理接口 修正 / #1590 开放平台刷新AccessToken同步更新RefreshToken
* #1474 新增客户联系「联系我」管理接口 * fix #1590 提及的me.chanjar.weixin.open.api.impl.WxOpenComponentServiceImpl#getAuthorizerAccessToken()刷新AccessToken后没有同步对应的refreshToken * 补充 me.chanjar.weixin.open.api.impl.WxOpenInMemoryConfigStorage#updateToken 方法对 expireInSeconds 边界判断
1 parent 04fb35d commit 0758049

12 files changed

+563
-19
lines changed

weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java

+78
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package me.chanjar.weixin.cp.api;
22

3+
import lombok.NonNull;
34
import me.chanjar.weixin.common.error.WxErrorException;
45
import me.chanjar.weixin.cp.bean.*;
56

@@ -15,6 +16,83 @@
1516
* @author <a href="https://github.com/JoeCao">JoeCao</a>
1617
*/
1718
public interface WxCpExternalContactService {
19+
20+
/**
21+
* 配置客户联系「联系我」方式
22+
* <pre>
23+
* 企业可以在管理后台-客户联系中配置成员的「联系我」的二维码或者小程序按钮,客户通过扫描二维码或点击小程序上的按钮,即可获取成员联系方式,主动联系到成员。
24+
* 企业可通过此接口为具有客户联系功能的成员生成专属的「联系我」二维码或者「联系我」按钮。
25+
* 如果配置的是「联系我」按钮,需要开发者的小程序接入小程序插件。
26+
*
27+
* 注意:
28+
* 通过API添加的「联系我」不会在管理端进行展示,每个企业可通过API最多配置50万个「联系我」。
29+
* 用户需要妥善存储返回的config_id,config_id丢失可能导致用户无法编辑或删除「联系我」。
30+
* 临时会话模式不占用「联系我」数量,但每日最多添加10万个,并且仅支持单人。
31+
* 临时会话模式的二维码,添加好友完成后该二维码即刻失效。
32+
* </pre>
33+
*
34+
* @param info 客户联系「联系我」方式
35+
* @return
36+
* @throws WxErrorException
37+
*/
38+
WxCpContactWayResult addContactWay(@NonNull WxCpContactWayInfo info) throws WxErrorException;
39+
40+
/**
41+
* 获取企业已配置的「联系我」方式
42+
*
43+
* <pre>
44+
* <b>批量</b>获取企业配置的「联系我」二维码和「联系我」小程序按钮。
45+
* </pre>
46+
*
47+
* @param configId 联系方式的配置id,必填
48+
* @return
49+
* @throws WxErrorException
50+
*/
51+
WxCpContactWayInfo getContactWay(@NonNull String configId) throws WxErrorException;
52+
53+
/**
54+
* 更新企业已配置的「联系我」方式
55+
*
56+
* <pre>
57+
* 更新企业配置的「联系我」二维码和「联系我」小程序按钮中的信息,如使用人员和备注等。
58+
* </pre>
59+
*
60+
* @param info 客户联系「联系我」方式
61+
* @return
62+
* @throws WxErrorException
63+
*/
64+
WxCpBaseResp updateContactWay(@NonNull WxCpContactWayInfo info) throws WxErrorException;
65+
66+
/**
67+
* 删除企业已配置的「联系我」方式
68+
*
69+
* <pre>
70+
* 删除一个已配置的「联系我」二维码或者「联系我」小程序按钮。
71+
* </pre>
72+
*
73+
* @param configId 企业联系方式的配置id,必填
74+
* @return
75+
* @throws WxErrorException
76+
*/
77+
WxCpBaseResp deleteContactWay(@NonNull String configId) throws WxErrorException;
78+
79+
/**
80+
* 结束临时会话
81+
*
82+
* <pre>
83+
* 将指定的企业成员和客户之前的临时会话断开,断开前会自动下发已配置的结束语。
84+
*
85+
* 注意:请保证传入的企业成员和客户之间有仍然有效的临时会话, 通过<b>其他方式的添加外部联系人无法通过此接口关闭会话</b>。
86+
* </pre>
87+
*
88+
* @param userId
89+
* @param externalUserId
90+
* @return
91+
* @throws WxErrorException
92+
*/
93+
WxCpBaseResp closeTempChat(@NonNull String userId, @NonNull String externalUserId) throws WxErrorException;
94+
95+
1896
/**
1997
* 获取外部联系人详情.
2098
* <pre>

weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java

+66
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
import com.google.gson.Gson;
44
import com.google.gson.JsonObject;
5+
import lombok.NonNull;
56
import lombok.RequiredArgsConstructor;
67
import me.chanjar.weixin.common.error.WxCpErrorMsgEnum;
78
import me.chanjar.weixin.common.error.WxErrorException;
89
import me.chanjar.weixin.cp.api.WxCpExternalContactService;
910
import me.chanjar.weixin.cp.api.WxCpService;
1011
import me.chanjar.weixin.cp.bean.*;
1112
import org.apache.commons.lang3.ArrayUtils;
13+
import org.apache.commons.lang3.StringUtils;
1214

1315
import java.util.Collections;
1416
import java.util.Date;
@@ -23,6 +25,70 @@
2325
public class WxCpExternalContactServiceImpl implements WxCpExternalContactService {
2426
private final WxCpService mainService;
2527

28+
@Override
29+
public WxCpContactWayResult addContactWay(@NonNull WxCpContactWayInfo info) throws WxErrorException {
30+
31+
if (info.getUsers() != null && info.getUsers().size() > 100) {
32+
throw new RuntimeException("「联系我」使用人数默认限制不超过100人(包括部门展开后的人数)");
33+
}
34+
35+
final String url = this.mainService.getWxCpConfigStorage().getApiUrl(ADD_CONTACT_WAY);
36+
String responseContent = this.mainService.post(url, info.toJson());
37+
38+
return WxCpContactWayResult.fromJson(responseContent);
39+
}
40+
41+
@Override
42+
public WxCpContactWayInfo getContactWay(@NonNull String configId) throws WxErrorException {
43+
JsonObject json = new JsonObject();
44+
json.addProperty("config_id", configId);
45+
46+
final String url = this.mainService.getWxCpConfigStorage().getApiUrl(GET_CONTACT_WAY);
47+
String responseContent = this.mainService.post(url, json.toString());
48+
49+
return WxCpContactWayInfo.fromJson(responseContent);
50+
}
51+
52+
@Override
53+
public WxCpBaseResp updateContactWay(@NonNull WxCpContactWayInfo info) throws WxErrorException {
54+
if (StringUtils.isBlank(info.getConfigId())) {
55+
throw new RuntimeException("更新「联系我」方式需要指定configId");
56+
}
57+
if (info.getUsers() != null && info.getUsers().size() > 100) {
58+
throw new RuntimeException("「联系我」使用人数默认限制不超过100人(包括部门展开后的人数)");
59+
}
60+
61+
final String url = this.mainService.getWxCpConfigStorage().getApiUrl(UPDATE_CONTACT_WAY);
62+
String responseContent = this.mainService.post(url, info.toJson());
63+
64+
return WxCpBaseResp.fromJson(responseContent);
65+
}
66+
67+
@Override
68+
public WxCpBaseResp deleteContactWay(@NonNull String configId) throws WxErrorException {
69+
JsonObject json = new JsonObject();
70+
json.addProperty("config_id",configId);
71+
72+
final String url = this.mainService.getWxCpConfigStorage().getApiUrl(DEL_CONTACT_WAY);
73+
String responseContent = this.mainService.post(url, json.toString());
74+
75+
return WxCpBaseResp.fromJson(responseContent);
76+
}
77+
78+
@Override
79+
public WxCpBaseResp closeTempChat(@NonNull String userId, @NonNull String externalUserId) throws WxErrorException {
80+
81+
JsonObject json = new JsonObject();
82+
json.addProperty("userid",userId);
83+
json.addProperty("external_userid",externalUserId);
84+
85+
86+
final String url = this.mainService.getWxCpConfigStorage().getApiUrl(CLOSE_TEMP_CHAT);
87+
String responseContent = this.mainService.post(url, json.toString());
88+
89+
return WxCpBaseResp.fromJson(responseContent);
90+
}
91+
2692
@Override
2793
public WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException {
2894
final String url = this.mainService.getWxCpConfigStorage().getApiUrl(GET_EXTERNAL_CONTACT + userId);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
package me.chanjar.weixin.cp.bean;
2+
3+
import com.google.gson.annotations.JsonAdapter;
4+
import com.google.gson.annotations.SerializedName;
5+
import lombok.Data;
6+
import lombok.NoArgsConstructor;
7+
import me.chanjar.weixin.cp.util.json.WxCpConclusionAdapter;
8+
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
9+
10+
import java.util.List;
11+
12+
/**
13+
* 「联系我」方式 对象
14+
*
15+
* @author element
16+
*/
17+
@Data
18+
@NoArgsConstructor
19+
public class WxCpContactWayInfo {
20+
21+
/**
22+
* 联系方式的配置id
23+
*/
24+
@SerializedName("config_id")
25+
private String configId;
26+
27+
/**
28+
* <pre>
29+
* 必填
30+
* 联系方式类型,1-单人, 2-多人
31+
* </pre>
32+
*/
33+
private TYPE type;
34+
35+
/**
36+
* <pre>
37+
* 必填
38+
* 场景,1-在小程序中联系,2-通过二维码联系
39+
* </pre>
40+
*/
41+
private SCENE scene;
42+
43+
/**
44+
* <pre>
45+
* 非必填
46+
* 在小程序中联系时使用的控件样式
47+
* <b>单人样式(type=1)时可选1,2,3</b>
48+
* <b>多人样式(type=2)时可选1,2</b>
49+
* </pre>
50+
*/
51+
private Integer style;
52+
53+
/**
54+
* <pre>
55+
* 非必填
56+
* 联系方式的备注信息,用于助记,不超过30个字符
57+
* </pre>
58+
*/
59+
private String remark;
60+
61+
/**
62+
* <pre>
63+
* 非必填
64+
* 外部客户添加时是否无需验证,默认为true
65+
* </pre>
66+
*/
67+
@SerializedName("skip_verify")
68+
private Boolean skipVerify = Boolean.TRUE;
69+
70+
/**
71+
* <pre>
72+
* 非必填
73+
* 企业自定义的state参数,用于区分不同的添加渠道,在调用“获取外部联系人详情(WxCpExternalContactService.getContactDetail)” 时会返回该参数值,不超过30个字符
74+
* </pre>
75+
*/
76+
private String state;
77+
78+
/**
79+
* <pre>
80+
* 使用该联系方式的用户userID列表,在type为1时为必填,且只能有一个
81+
* </pre>
82+
*/
83+
@SerializedName("user")
84+
private List<String> users;
85+
86+
87+
/**
88+
* <pre>
89+
* 非必填
90+
* 使用该联系方式的部门id列表,只在type为2时有效
91+
* </pre>
92+
*/
93+
@SerializedName("party")
94+
private List<String> partys;
95+
96+
/**
97+
* <pre>
98+
* 非必填
99+
* 是否临时会话模式,true表示使用临时会话模式,默认为false
100+
* </pre>
101+
*/
102+
@SerializedName("is_temp")
103+
private Boolean isTemp = Boolean.FALSE;
104+
105+
/**
106+
* <pre>
107+
* 非必填
108+
* 临时会话二维码有效期,以秒为单位。该参数仅在is_temp为true时有效,默认7天
109+
* </pre>
110+
*/
111+
@SerializedName("expires_in")
112+
private Integer expiresIn;
113+
114+
/**
115+
* <pre>
116+
* 非必填
117+
* 临时会话有效期,以秒为单位。该参数仅在is_temp为true时有效,默认为添加好友后24小时
118+
* </pre>
119+
*/
120+
@SerializedName("chat_expires_in")
121+
private Integer chatExpiresIn;
122+
123+
/**
124+
* <pre>
125+
* 非必填
126+
* 可进行临时会话的客户unionid,该参数仅在is_temp为true时有效,如不指定则不进行限制
127+
* </pre>
128+
*/
129+
@SerializedName("unionid")
130+
private String unionId;
131+
132+
/**
133+
* <pre>
134+
* 非必填
135+
* 结束语,会话结束时自动发送给客户,可参考“结束语定义”,仅在is_temp为true时有效
136+
* </pre>
137+
*/
138+
private Conclusion conclusions;
139+
140+
public static WxCpContactWayInfo fromJson(String json) {
141+
return WxCpGsonBuilder.create().fromJson(json, WxCpContactWayInfo.class);
142+
}
143+
144+
public String toJson() {
145+
return WxCpGsonBuilder.create().toJson(this);
146+
}
147+
148+
/**
149+
* 结束语定义
150+
*/
151+
@Data
152+
@JsonAdapter(WxCpConclusionAdapter.class)
153+
public static class Conclusion {
154+
private String textContent;
155+
private String imgMediaId;
156+
private String imgPicUrl;
157+
private String linkTitle;
158+
private String linkPicUrl;
159+
private String linkDesc;
160+
private String linkUrl;
161+
private String miniProgramTitle;
162+
private String miniProgramPicMediaId;
163+
private String miniProgramAppId;
164+
private String miniProgramPage;
165+
}
166+
167+
public enum TYPE {
168+
/**
169+
* 单人
170+
*/
171+
@SerializedName("1")
172+
SIGLE,
173+
174+
/**
175+
* 多人
176+
*/
177+
@SerializedName("2")
178+
MULTI;
179+
180+
}
181+
182+
public enum SCENE {
183+
184+
/**
185+
* 在小程序中联系
186+
*/
187+
@SerializedName("1")
188+
MINIPROGRAM,
189+
190+
/**
191+
* 通过二维码联系
192+
*/
193+
@SerializedName("2")
194+
QRCODE;
195+
196+
}
197+
198+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package me.chanjar.weixin.cp.bean;
2+
3+
import com.google.gson.annotations.SerializedName;
4+
import lombok.Data;
5+
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
6+
7+
/**
8+
* 「联系我」方式 处理结果
9+
*/
10+
@Data
11+
public class WxCpContactWayResult extends WxCpBaseResp {
12+
@SerializedName("config_id")
13+
private String configId;
14+
15+
public static WxCpContactWayResult fromJson(String json) {
16+
return WxCpGsonBuilder.create().fromJson(json, WxCpContactWayResult.class);
17+
}
18+
}

0 commit comments

Comments
 (0)