Skip to content

Commit c7e4e8b

Browse files
authored
新增视频号小店商家客服服务与数据模型
1 parent ac92b13 commit c7e4e8b

9 files changed

Lines changed: 325 additions & 0 deletions

File tree

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package me.chanjar.weixin.channel.api;
2+
3+
import me.chanjar.weixin.channel.bean.kf.WxChannelKfSendMsgParam;
4+
import me.chanjar.weixin.channel.bean.kf.WxChannelKfSendMsgResponse;
5+
import me.chanjar.weixin.common.error.WxErrorException;
6+
7+
/**
8+
* 视频号小店 商家客服服务
9+
*
10+
* @author <a href="https://github.com/github-copilot">GitHub Copilot</a>
11+
*/
12+
public interface WxChannelKfService {
13+
14+
/**
15+
* 上传多媒体资源.
16+
*
17+
* @param openId 用户 open_id
18+
* @param msgType 文件类型,仅支持:video/file/image
19+
* @param file 文件字节内容
20+
* @return cos_url
21+
*
22+
* @throws WxErrorException 异常
23+
*/
24+
String uploadMedia(String openId, String msgType, byte[] file) throws WxErrorException;
25+
26+
/**
27+
* 上传多媒体资源.
28+
*
29+
* @param openId 用户 open_id
30+
* @param msgType 文件类型,仅支持:video/file/image
31+
* @param fileName 文件名
32+
* @param file 文件字节内容
33+
* @return cos_url
34+
*
35+
* @throws WxErrorException 异常
36+
*/
37+
String uploadMedia(String openId, String msgType, String fileName, byte[] file) throws WxErrorException;
38+
39+
/**
40+
* 发送客服消息.
41+
*
42+
* @param param 请求参数
43+
* @return 发送结果
44+
*
45+
* @throws WxErrorException 异常
46+
*/
47+
WxChannelKfSendMsgResponse sendMessage(WxChannelKfSendMsgParam param) throws WxErrorException;
48+
}

weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelService.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,4 +182,11 @@ public interface WxChannelService extends BaseWxChannelService {
182182
*/
183183
WxChannelLiveDashboardService getLiveDashboardService();
184184

185+
/**
186+
* 商家客服服务
187+
*
188+
* @return 商家客服服务
189+
*/
190+
WxChannelKfService getKfService();
191+
185192
}

weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/BaseWxChannelServiceImpl.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ public abstract class BaseWxChannelServiceImpl<H, P> implements WxChannelService
6060
private WxChannelVipService vipService = null;
6161
private WxChannelCompassFinderService compassFinderService = null;
6262
private WxChannelLiveDashboardService liveDashboardService = null;
63+
private WxChannelKfService kfService = null;
6364

6465
protected WxChannelConfig config;
6566
private int retrySleepMillis = 1000;
@@ -473,4 +474,12 @@ public synchronized WxChannelLiveDashboardService getLiveDashboardService() {
473474
return liveDashboardService;
474475
}
475476

477+
@Override
478+
public synchronized WxChannelKfService getKfService() {
479+
if (kfService == null) {
480+
kfService = new WxChannelKfServiceImpl(this);
481+
}
482+
return kfService;
483+
}
484+
476485
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package me.chanjar.weixin.channel.api.impl;
2+
3+
import lombok.extern.slf4j.Slf4j;
4+
import me.chanjar.weixin.channel.api.WxChannelKfService;
5+
import me.chanjar.weixin.channel.bean.kf.WxChannelKfCosUploadResponse;
6+
import me.chanjar.weixin.channel.bean.kf.WxChannelKfSendMsgParam;
7+
import me.chanjar.weixin.channel.bean.kf.WxChannelKfSendMsgResponse;
8+
import me.chanjar.weixin.channel.util.ResponseUtils;
9+
import me.chanjar.weixin.common.bean.CommonUploadParam;
10+
import me.chanjar.weixin.common.error.WxErrorException;
11+
12+
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Kf.COS_UPLOAD_URL;
13+
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Kf.SEND_MSG_URL;
14+
15+
/**
16+
* 视频号小店 商家客服服务实现
17+
*
18+
* @author <a href="https://github.com/github-copilot">GitHub Copilot</a>
19+
*/
20+
@Slf4j
21+
public class WxChannelKfServiceImpl implements WxChannelKfService {
22+
23+
/** 微信商店服务 */
24+
private final BaseWxChannelServiceImpl<?, ?> shopService;
25+
26+
public WxChannelKfServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {
27+
this.shopService = shopService;
28+
}
29+
30+
@Override
31+
public String uploadMedia(String openId, String msgType, byte[] file) throws WxErrorException {
32+
return uploadMedia(openId, msgType, null, file);
33+
}
34+
35+
@Override
36+
public String uploadMedia(String openId, String msgType, String fileName, byte[] file) throws WxErrorException {
37+
CommonUploadParam uploadParam = CommonUploadParam.fromBytes("file", fileName, file)
38+
.addFormField("open_id", openId)
39+
.addFormField("msg_type", msgType);
40+
String resJson = shopService.upload(COS_UPLOAD_URL, uploadParam);
41+
WxChannelKfCosUploadResponse response = ResponseUtils.decode(resJson, WxChannelKfCosUploadResponse.class);
42+
return response.getCosUrl();
43+
}
44+
45+
@Override
46+
public WxChannelKfSendMsgResponse sendMessage(WxChannelKfSendMsgParam param) throws WxErrorException {
47+
String resJson = shopService.post(SEND_MSG_URL, param);
48+
return ResponseUtils.decode(resJson, WxChannelKfSendMsgResponse.class);
49+
}
50+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package me.chanjar.weixin.channel.bean.kf;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import lombok.Data;
5+
import lombok.EqualsAndHashCode;
6+
import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
7+
8+
import java.io.Serializable;
9+
10+
/**
11+
* 上传多媒体资源返回结果
12+
*
13+
* @author <a href="https://github.com/github-copilot">GitHub Copilot</a>
14+
*/
15+
@Data
16+
@EqualsAndHashCode(callSuper = true)
17+
public class WxChannelKfCosUploadResponse extends WxChannelBaseResponse implements Serializable {
18+
19+
private static final long serialVersionUID = -8073026558742450133L;
20+
21+
/** 多媒体 cos_url */
22+
@JsonProperty("cos_url")
23+
private String cosUrl;
24+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package me.chanjar.weixin.channel.bean.kf;
2+
3+
import com.fasterxml.jackson.annotation.JsonInclude;
4+
import com.fasterxml.jackson.annotation.JsonInclude.Include;
5+
import com.fasterxml.jackson.annotation.JsonProperty;
6+
import lombok.AllArgsConstructor;
7+
import lombok.Data;
8+
import lombok.NoArgsConstructor;
9+
10+
import java.io.Serializable;
11+
12+
/**
13+
* 发送客服消息请求参数
14+
*
15+
* @author <a href="https://github.com/github-copilot">GitHub Copilot</a>
16+
*/
17+
@Data
18+
@NoArgsConstructor
19+
@AllArgsConstructor
20+
@JsonInclude(Include.NON_NULL)
21+
public class WxChannelKfSendMsgParam implements Serializable {
22+
23+
private static final long serialVersionUID = -7384287911696365032L;
24+
25+
/** 唯一任务ID,填写后按任务ID去重 */
26+
@JsonProperty("request_id")
27+
private String requestId;
28+
29+
/** 用户 open_id */
30+
@JsonProperty("open_id")
31+
private String openId;
32+
33+
/** 消息类型 */
34+
@JsonProperty("msg_type")
35+
private String msgType;
36+
37+
/** 文本消息 */
38+
@JsonProperty("text")
39+
private TextMessage text;
40+
41+
/** 图片消息 */
42+
@JsonProperty("image")
43+
private CosUrlMessage image;
44+
45+
/** 视频消息 */
46+
@JsonProperty("video")
47+
private CosUrlMessage video;
48+
49+
/** 文件消息 */
50+
@JsonProperty("file")
51+
private CosUrlMessage file;
52+
53+
/** 商品卡片消息 */
54+
@JsonProperty("product_share")
55+
private ProductShareMessage productShare;
56+
57+
/** 订单卡片消息 */
58+
@JsonProperty("order_share")
59+
private OrderShareMessage orderShare;
60+
61+
@Data
62+
@NoArgsConstructor
63+
@AllArgsConstructor
64+
public static class TextMessage implements Serializable {
65+
66+
private static final long serialVersionUID = -5001585611550636499L;
67+
68+
@JsonProperty("content")
69+
private String content;
70+
}
71+
72+
@Data
73+
@NoArgsConstructor
74+
@AllArgsConstructor
75+
public static class CosUrlMessage implements Serializable {
76+
77+
private static final long serialVersionUID = 8403720861098936947L;
78+
79+
@JsonProperty("cos_url")
80+
private String cosUrl;
81+
}
82+
83+
@Data
84+
@NoArgsConstructor
85+
@AllArgsConstructor
86+
public static class ProductShareMessage implements Serializable {
87+
88+
private static final long serialVersionUID = -3049552399099249795L;
89+
90+
@JsonProperty("product_id")
91+
private String productId;
92+
}
93+
94+
@Data
95+
@NoArgsConstructor
96+
@AllArgsConstructor
97+
public static class OrderShareMessage implements Serializable {
98+
99+
private static final long serialVersionUID = 7136546635145180607L;
100+
101+
@JsonProperty("order_id")
102+
private String orderId;
103+
}
104+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package me.chanjar.weixin.channel.bean.kf;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import lombok.Data;
5+
import lombok.EqualsAndHashCode;
6+
import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
7+
8+
import java.io.Serializable;
9+
10+
/**
11+
* 发送客服消息返回结果
12+
*
13+
* @author <a href="https://github.com/github-copilot">GitHub Copilot</a>
14+
*/
15+
@Data
16+
@EqualsAndHashCode(callSuper = true)
17+
public class WxChannelKfSendMsgResponse extends WxChannelBaseResponse implements Serializable {
18+
19+
private static final long serialVersionUID = -4994877385473101709L;
20+
21+
/** 消息ID */
22+
@JsonProperty("msg_id")
23+
private String msgId;
24+
}

weixin-java-channel/src/main/java/me/chanjar/weixin/channel/constant/WxChannelApiUrlConstants.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,15 @@ public interface Order {
217217
String DECODE_SENSITIVE_INFO_URL = "https://api.weixin.qq.com/channels/ec/order/sensitiveinfo/decode";
218218
}
219219

220+
/** 商家客服相关接口 */
221+
public interface Kf {
222+
223+
/** 上传多媒体资源 */
224+
String COS_UPLOAD_URL = "https://api.weixin.qq.com/channels/ec/commkf/cosupload";
225+
/** 发送消息 */
226+
String SEND_MSG_URL = "https://api.weixin.qq.com/channels/ec/commkf/sendmsg";
227+
}
228+
220229
/** 售后相关接口 */
221230
public interface AfterSale {
222231

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package me.chanjar.weixin.channel.bean.kf;
2+
3+
import me.chanjar.weixin.channel.util.JsonUtils;
4+
import org.testng.annotations.Test;
5+
6+
import static org.testng.Assert.assertEquals;
7+
import static org.testng.Assert.assertNotNull;
8+
import static org.testng.Assert.assertTrue;
9+
10+
/**
11+
* @author <a href="https://github.com/github-copilot">GitHub Copilot</a>
12+
*/
13+
public class WxChannelKfBeanTest {
14+
15+
@Test
16+
public void testSendMsgParamEncode() {
17+
WxChannelKfSendMsgParam param = new WxChannelKfSendMsgParam();
18+
param.setRequestId("63abd34b-656b-4082-b364-5f74226e1a20");
19+
param.setOpenId("o7eep4jVQelr2eyoDSmE1xxxxxx");
20+
param.setMsgType("text");
21+
param.setText(new WxChannelKfSendMsgParam.TextMessage("测试消息123"));
22+
23+
String json = JsonUtils.encode(param);
24+
assertNotNull(json);
25+
assertTrue(json.contains("\"request_id\":\"63abd34b-656b-4082-b364-5f74226e1a20\""));
26+
assertTrue(json.contains("\"open_id\":\"o7eep4jVQelr2eyoDSmE1xxxxxx\""));
27+
assertTrue(json.contains("\"msg_type\":\"text\""));
28+
assertTrue(json.contains("\"text\":{\"content\":\"测试消息123\"}"));
29+
}
30+
31+
@Test
32+
public void testSendMsgResponseDecode() {
33+
String json = "{\"msg_id\":\"3886839959369302016\",\"errmsg\":\"ok\",\"errcode\":0}";
34+
WxChannelKfSendMsgResponse response = JsonUtils.decode(json, WxChannelKfSendMsgResponse.class);
35+
assertNotNull(response);
36+
assertEquals(response.getMsgId(), "3886839959369302016");
37+
assertEquals(response.getErrCode(), 0);
38+
assertEquals(response.getErrMsg(), "ok");
39+
}
40+
41+
@Test
42+
public void testCosUploadResponseDecode() {
43+
String json = "{\"cos_url\":\"https://channels.weixin.qq.com/shop/commkf/downloadmedia?encrypted_param=xxxxx&timestamp=xxxxx&openid=xxxxxx&msg_type=7\",\"errmsg\":\"ok\",\"errcode\":0}";
44+
WxChannelKfCosUploadResponse response = JsonUtils.decode(json, WxChannelKfCosUploadResponse.class);
45+
assertNotNull(response);
46+
assertTrue(response.getCosUrl().contains("channels.weixin.qq.com/shop/commkf/downloadmedia"));
47+
assertEquals(response.getErrCode(), 0);
48+
assertEquals(response.getErrMsg(), "ok");
49+
}
50+
}

0 commit comments

Comments
 (0)