diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java index e5c27350..99dcaba9 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java @@ -1,16 +1,21 @@ package me.chanjar.weixin.mp.api; +import java.io.File; +import java.util.Date; + import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfAccountRequest; -import me.chanjar.weixin.mp.bean.kefu.result.*; - -import java.io.File; -import java.util.Date; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfMsgList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfOnlineList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionGetResult; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionWaitCaseList; /** *
- * 客服接口 ,
+ * 客服接口.
  * 注意:命名采用kefu拼音的原因是:其英文CustomerService如果再加上Service后缀显得有点啰嗦,如果不加又显得表意不完整。
  * 
* @@ -30,7 +35,8 @@ public interface WxMpKefuService { String KFSESSION_GET_SESSION = "https://api.weixin.qq.com/customservice/kfsession/getsession?openid=%s"; String KFSESSION_GET_SESSION_LIST = "https://api.weixin.qq.com/customservice/kfsession/getsessionlist?kf_account=%s"; String KFSESSION_GET_WAIT_CASE = "https://api.weixin.qq.com/customservice/kfsession/getwaitcase"; - String MSGRECORD_GET_MSG_LIST = "https://api.weixin.qq.com/customservice/msgrecord/getmsglist"; + String MSG_RECORD_LIST = "https://api.weixin.qq.com/customservice/msgrecord/getmsglist"; + String CUSTOM_TYPING = "https://api.weixin.qq.com/cgi-bin/message/custom/typing"; /** *
@@ -38,6 +44,8 @@ public interface WxMpKefuService {
    * 详情请见: 发送客服消息
    * 接口url格式:https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
    * 
+ * + * @throws WxErrorException 异常 */ boolean sendKefuMessage(WxMpKefuMessage message) throws WxErrorException; @@ -49,6 +57,8 @@ public interface WxMpKefuService { * 详情请见:客服管理 * 接口url格式:https://api.weixin.qq.com/cgi-bin/customservice/getkflist?access_token=ACCESS_TOKEN * + * + * @throws WxErrorException 异常 */ WxMpKfList kfList() throws WxErrorException; @@ -58,6 +68,8 @@ public interface WxMpKefuService { * 详情请见:客服管理 * 接口url格式:https://api.weixin.qq.com/cgi-bin/customservice/getonlinekflist?access_token=ACCESS_TOKEN * + * + * @throws WxErrorException 异常 */ WxMpKfOnlineList kfOnlineList() throws WxErrorException; @@ -67,6 +79,8 @@ public interface WxMpKefuService { * 详情请见:客服管理 * 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/add?access_token=ACCESS_TOKEN * + * + * @throws WxErrorException 异常 */ boolean kfAccountAdd(WxMpKfAccountRequest request) throws WxErrorException; @@ -85,6 +99,8 @@ public interface WxMpKefuService { * 详情请见:客服管理 * 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/inviteworker?access_token=ACCESS_TOKEN * + * + * @throws WxErrorException 异常 */ boolean kfAccountInviteWorker(WxMpKfAccountRequest request) throws WxErrorException; @@ -94,8 +110,10 @@ public interface WxMpKefuService { * 详情请见:客服管理 * 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/uploadheadimg?access_token=ACCESS_TOKEN&kf_account=KFACCOUNT * + * + * @throws WxErrorException 异常 */ - boolean kfAccountUploadHeadImg(String kfAccount, File imgFile) throws WxErrorException; + boolean kfAccountUploadHeadImg(String kfAccount, File imgFile) throws WxErrorException; /** *
@@ -103,6 +121,8 @@ public interface WxMpKefuService {
    * 详情请见:客服管理
    * 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/del?access_token=ACCESS_TOKEN&kf_account=KFACCOUNT
    * 
+ * + * @throws WxErrorException 异常 */ boolean kfAccountDel(String kfAccount) throws WxErrorException; @@ -115,6 +135,8 @@ public interface WxMpKefuService { * 详情请见:客服会话控制接口 * 接口url格式: https://api.weixin.qq.com/customservice/kfsession/create?access_token=ACCESS_TOKEN * + * + * @throws WxErrorException 异常 */ boolean kfSessionCreate(String openid, String kfAccount) throws WxErrorException; @@ -125,6 +147,8 @@ public interface WxMpKefuService { * 详情请见:客服会话控制接口 * 接口url格式: https://api.weixin.qq.com/customservice/kfsession/close?access_token=ACCESS_TOKEN * + * + * @throws WxErrorException 异常 */ boolean kfSessionClose(String openid, String kfAccount) throws WxErrorException; @@ -135,6 +159,8 @@ public interface WxMpKefuService { * 详情请见:客服会话控制接口 * 接口url格式: https://api.weixin.qq.com/customservice/kfsession/getsession?access_token=ACCESS_TOKEN&openid=OPENID * + * + * @throws WxErrorException 异常 */ WxMpKfSessionGetResult kfSessionGet(String openid) throws WxErrorException; @@ -145,6 +171,8 @@ public interface WxMpKefuService { * 详情请见:客服会话控制 * 接口url格式: https://api.weixin.qq.com/customservice/kfsession/getsessionlist?access_token=ACCESS_TOKEN&kf_account=KFACCOUNT * + * + * @throws WxErrorException 异常 */ WxMpKfSessionList kfSessionList(String kfAccount) throws WxErrorException; @@ -155,6 +183,8 @@ public interface WxMpKefuService { * 详情请见:客服会话控制 * 接口url格式: https://api.weixin.qq.com/customservice/kfsession/getwaitcase?access_token=ACCESS_TOKEN * + * + * @throws WxErrorException 异常 */ WxMpKfSessionWaitCaseList kfSessionGetWaitCase() throws WxErrorException; @@ -173,7 +203,7 @@ public interface WxMpKefuService { * @param msgId 消息id顺序从小到大,从1开始 * @param number 每次获取条数,最多10000条 * @return 聊天记录对象 - * @throws WxErrorException + * @throws WxErrorException 异常 */ WxMpKfMsgList kfMsgList(Date startTime, Date endTime, Long msgId, Integer number) throws WxErrorException; @@ -188,8 +218,27 @@ public interface WxMpKefuService { * @param startTime 起始时间 * @param endTime 结束时间 * @return 聊天记录对象 - * @throws WxErrorException + * @throws WxErrorException 异常 */ WxMpKfMsgList kfMsgList(Date startTime, Date endTime) throws WxErrorException; + /** + *
+   * 客服输入状态
+   * 开发者可通过调用“客服输入状态”接口,返回客服当前输入状态给用户。
+   * 此接口需要客服消息接口权限。
+   * 如果不满足发送客服消息的触发条件,则无法下发输入状态。
+   * 下发输入状态,需要客服之前30秒内跟用户有过消息交互。
+   * 在输入状态中(持续15s),不可重复下发输入态。
+   * 在输入状态中,如果向用户下发消息,会同时取消输入状态。
+   *
+   * 详情请见:客服输入状态
+   * 接口url格式:https://api.weixin.qq.com/cgi-bin/message/custom/typing?access_token=ACCESS_TOKEN
+   * 
+ * + * @param openid 用户id + * @param command "Typing":对用户下发“正在输入"状态 "CancelTyping":取消对用户的”正在输入"状态 + * @throws WxErrorException 异常 + */ + boolean sendKfTypingState(String openid, String command) throws WxErrorException; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java index 604ce832..7707c567 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java @@ -1,8 +1,14 @@ package me.chanjar.weixin.mp.api.impl; +import java.io.File; +import java.util.Date; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.google.gson.JsonObject; -import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.mp.api.WxMpKefuService; @@ -10,12 +16,12 @@ import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfAccountRequest; import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfSessionRequest; -import me.chanjar.weixin.mp.bean.kefu.result.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.util.Date; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfMsgList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfOnlineList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionGetResult; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionList; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionWaitCaseList; /** * @author Binary Wang @@ -120,12 +126,12 @@ public class WxMpKefuServiceImpl implements WxMpKefuService { } JsonObject param = new JsonObject(); - param.addProperty("starttime", startTime.getTime() / 1000); //starttime 起始时间,unix时间戳 - param.addProperty("endtime", endTime.getTime() / 1000); //endtime 结束时间,unix时间戳,每次查询时段不能超过24小时 - param.addProperty("msgid", msgId); //msgid 消息id顺序从小到大,从1开始 - param.addProperty("number", number); //number 每次获取条数,最多10000条 + param.addProperty("starttime", startTime.getTime() / 1000); + param.addProperty("endtime", endTime.getTime() / 1000); + param.addProperty("msgid", msgId); + param.addProperty("number", number); - String responseContent = this.wxMpService.post(MSGRECORD_GET_MSG_LIST, param.toString()); + String responseContent = this.wxMpService.post(MSG_RECORD_LIST, param.toString()); return WxMpKfMsgList.fromJson(responseContent); } @@ -149,4 +155,13 @@ public class WxMpKefuServiceImpl implements WxMpKefuService { return result; } + @Override + public boolean sendKfTypingState(String openid, String command) throws WxErrorException { + JsonObject params = new JsonObject(); + params.addProperty("touser", openid); + params.addProperty("command", command); + String responseContent = this.wxMpService.post(CUSTOM_TYPING, params.toString()); + return responseContent != null; + } + } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImplTest.java index 13a161a1..712e8874 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImplTest.java @@ -1,5 +1,11 @@ package me.chanjar.weixin.mp.api.impl; +import java.io.File; +import java.util.Date; + +import org.joda.time.DateTime; +import org.testng.annotations.*; + import com.google.inject.Inject; import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.error.WxErrorException; @@ -8,12 +14,13 @@ import me.chanjar.weixin.mp.api.test.ApiTestModule; import me.chanjar.weixin.mp.api.test.TestConfigStorage; import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfAccountRequest; -import me.chanjar.weixin.mp.bean.kefu.result.*; -import org.joda.time.DateTime; -import org.testng.annotations.*; - -import java.io.File; -import java.util.Date; +import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfInfo; +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 static org.assertj.core.api.Assertions.assertThat; @@ -134,8 +141,7 @@ public class WxMpKefuServiceImplTest { } @Test(dataProvider = "getKfAccountAndOpenid") - public void testKfSessionClose(String kfAccount, String openid) - throws WxErrorException { + public void testKfSessionClose(String kfAccount, String openid) throws WxErrorException { boolean result = this.wxService.getKefuService().kfSessionClose(openid, kfAccount); assertThat(result).isTrue(); } @@ -178,4 +184,11 @@ public class WxMpKefuServiceImplTest { assertThat(result).isNotNull(); System.err.println(result); } + + @Test + public void testSendKfTypingState() throws WxErrorException { + TestConfigStorage configStorage = (TestConfigStorage) this.wxService.getWxMpConfigStorage(); + boolean result = this.wxService.getKefuService().sendKfTypingState(configStorage.getOpenid(), "Typing"); + assertThat(result).isTrue(); + } }