diff --git a/spring-boot-starters/wx-java-cp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/cp/properties/WxCpProperties.java b/spring-boot-starters/wx-java-cp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/cp/properties/WxCpProperties.java index e4b200f1a25532199a85efeeb873a86767e2238c..b2cc778ac09d1c4d1606224e63ed42400520399a 100644 --- a/spring-boot-starters/wx-java-cp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/cp/properties/WxCpProperties.java +++ b/spring-boot-starters/wx-java-cp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/cp/properties/WxCpProperties.java @@ -38,6 +38,10 @@ public class WxCpProperties { * 微信企业号应用 EncodingAESKey */ private String aesKey; + /** + * 微信企业号应用 会话存档类库路径 + */ + private String msgAuditLibPath; /** * 配置存储策略,默认内存 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 f55672b0b433fdcf487ecd7c0c3749b5d14c90fd..d44791eb18e472573abb903a2f6f31889cb38e5d 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 @@ -1,19 +1,6 @@ package me.chanjar.weixin.common.util.crypto; -import java.io.StringReader; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Random; -import javax.crypto.Cipher; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - import com.google.common.base.CharMatcher; -import com.google.common.io.BaseEncoding; import lombok.AllArgsConstructor; import lombok.Data; import me.chanjar.weixin.common.error.WxRuntimeException; @@ -22,6 +9,18 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.InputSource; +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.io.StringReader; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Random; + /** *
* 对公众平台发送给公众账号的消息加解密示例代码. diff --git a/weixin-java-cp/src/main/java/com/tencent/wework/Finance.java b/weixin-java-cp/src/main/java/com/tencent/wework/Finance.java new file mode 100644 index 0000000000000000000000000000000000000000..e653fd0f479da772f853ce1aaea60fe22be4fc62 --- /dev/null +++ b/weixin-java-cp/src/main/java/com/tencent/wework/Finance.java @@ -0,0 +1,207 @@ +package com.tencent.wework; + +import lombok.extern.slf4j.Slf4j; + +/** + * 注意: + * 此类必须配置在com.tencent.wework路径底下,否则会报错: + * java.lang.UnsatisfiedLinkError: com.xxx.Finance.NewSdk() + *+ * Q:JAVA版本的sdk报错UnsatisfiedLinkError? + * A:请检查是否修改了sdk的包名。 + *
+ * 官方文档: + * https://developer.work.weixin.qq.com/document/path/91552 + * + * @author Wang_Wong + * @date 2022-01-17 + */ +@Slf4j +public class Finance { + + private static volatile long sdk = -1L; + private static Finance finance = null; + private static final String SO_FILE = "so"; + private static final String DLL_FILE = "dll"; + + public native static long NewSdk(); + + /** + * 初始化函数 + * Return值=0表示该API调用成功 + * + * @param [in] sdk NewSdk返回的sdk指针 + * @param [in] corpid 调用企业的企业id,例如:wwd08c8exxxx5ab44d,可以在企业微信管理端--我的企业--企业信息查看 + * @param [in] secret 聊天内容存档的Secret,可以在企业微信管理端--管理工具--聊天内容存档查看 + * @return 返回是否初始化成功 + * 0 - 成功 + * !=0 - 失败 + */ + public native static int Init(long sdk, String corpid, String secret); + + /** + * 拉取聊天记录函数 + * Return值=0表示该API调用成功 + * + * @param [in] sdk NewSdk返回的sdk指针 + * @param [in] seq 从指定的seq开始拉取消息,注意的是返回的消息从seq+1开始返回,seq为之前接口返回的最大seq值。首次使用请使用seq:0 + * @param [in] limit 一次拉取的消息条数,最大值1000条,超过1000条会返回错误 + * @param [in] proxy 使用代理的请求,需要传入代理的链接。如:socks5://10.0.0.1:8081 或者 http://10.0.0.1:8081 + * @param [in] passwd 代理账号密码,需要传入代理的账号密码。如 user_name:passwd_123 + * @param [out] chatDatas 返回本次拉取消息的数据,slice结构体.内容包括errcode/errmsg,以及每条消息内容。 + * @return 返回是否调用成功 + * 0 - 成功 + * !=0 - 失败 + */ + public native static int GetChatData(long sdk, long seq, long limit, String proxy, String passwd, long timeout, long chatData); + + /** + * 拉取媒体消息函数 + * Return值=0表示该API调用成功 + * + * @param [in] sdk NewSdk返回的sdk指针 + * @param [in] sdkFileid 从GetChatData返回的聊天消息中,媒体消息包括的sdkfileid + * @param [in] proxy 使用代理的请求,需要传入代理的链接。如:socks5://10.0.0.1:8081 或者 http://10.0.0.1:8081 + * @param [in] passwd 代理账号密码,需要传入代理的账号密码。如 user_name:passwd_123 + * @param [in] indexbuf 媒体消息分片拉取,需要填入每次拉取的索引信息。首次不需要填写,默认拉取512k,后续每次调用只需要将上次调用返回的outindexbuf填入即可。 + * @param [out] media_data 返回本次拉取的媒体数据.MediaData结构体.内容包括data(数据内容)/outindexbuf(下次索引)/is_finish(拉取完成标记) + * @return 返回是否调用成功 + * 0 - 成功 + * !=0 - 失败 + */ + public native static int GetMediaData(long sdk, String indexbuf, String sdkField, String proxy, String passwd, long timeout, long mediaData); + + /** + * @param [in] encrypt_key, getchatdata返回的encrypt_key + * @param [in] encrypt_msg, getchatdata返回的content + * @param [out] msg, 解密的消息明文 + * @return 返回是否调用成功 + * 0 - 成功 + * !=0 - 失败 + * @brief 解析密文 + */ + public native static int DecryptData(long sdk, String encrypt_key, String encrypt_msg, long msg); + + public native static void DestroySdk(long sdk); + + public native static long NewSlice(); + + /** + * @return + * @brief 释放slice,和NewSlice成对使用 + */ + public native static void FreeSlice(long slice); + + /** + * @return 内容 + * @brief 获取slice内容 + */ + public native static String GetContentFromSlice(long slice); + + /** + * @return 内容 + * @brief 获取slice内容长度 + */ + public native static int GetSliceLen(long slice); + + public native static long NewMediaData(); + + public native static void FreeMediaData(long mediaData); + + /** + * @return outindex + * @brief 获取mediadata outindex + */ + public native static String GetOutIndexBuf(long mediaData); + + /** + * @return data + * @brief 获取mediadata data数据 + */ + public native static byte[] GetData(long mediaData); + + public native static int GetIndexLen(long mediaData); + + public native static int GetDataLen(long mediaData); + + /** + * @return 1完成、0未完成 + * @brief 判断mediadata是否结束 + */ + public native static int IsMediaDataFinish(long mediaData); + + /** + * 判断Windows环境 + * + * @return + */ + public static boolean isWindows() { + String osName = System.getProperties().getProperty("os.name"); + log.info("Loading System Libraries, Current OS Version Is: {}", osName); + return osName.toUpperCase().contains("WINDOWS"); + } + + /** + * 加载系统类库 + * + * @param libFiles 类库配置文件 + * @param prefixPath 类库文件的前缀路径 + */ + public Finance(String[] libFiles, String prefixPath) { + boolean isWindows = Finance.isWindows(); + for (String file : libFiles) { + String suffix = file.substring(file.lastIndexOf(".") + 1); + if (isWindows) { + // 加载dll文件 + if (suffix.equalsIgnoreCase(DLL_FILE)) { + System.load(prefixPath + file); + } + } else { + // 加载so文件 + if (suffix.equalsIgnoreCase(SO_FILE)) { + System.load(prefixPath + file); + } + } + } + + } + + /** + * 初始化类库文件 + * + * @param libFiles + * @param prefixPath + * @return + */ + public synchronized static Finance loadingLibraries(String[] libFiles, String prefixPath) { + if (finance != null) { + return finance; + } + finance = new Finance(libFiles, prefixPath); + return finance; + } + + /** + * 单例sdk + * + * @return + */ + public synchronized static long SingletonSDK() { + if (sdk > 0) { + return sdk; + } + sdk = Finance.NewSdk(); + return sdk; + } + + /** + * 销毁sdk,保证线程可见性 + * + * @return + */ + public synchronized static void DestroySingletonSDK(long destroySDK) { + sdk = 0L; + Finance.DestroySdk(destroySDK); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMsgAuditService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMsgAuditService.java new file mode 100644 index 0000000000000000000000000000000000000000..63389aeb8cc0a8a78bf12a8ede81b5ef9adb954f --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMsgAuditService.java @@ -0,0 +1,108 @@ +package me.chanjar.weixin.cp.api; + +import lombok.NonNull; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.cp.bean.msgaudit.*; + +import java.util.List; + +/** + * 会话内容存档接口. + * 官方文档:https://developer.work.weixin.qq.com/document/path/91360 + *
+ * 如需自行实现,亦可调用Finance类库函数,进行实现: + * com.tencent.wework.Finance + * + * @author Wang_Wong + * @date 2022-01-14 + */ +public interface WxCpMsgAuditService { + + /** + * 拉取聊天记录函数 + * + * @param seq 从指定的seq开始拉取消息,注意的是返回的消息从seq+1开始返回,seq为之前接口返回的最大seq值。首次使用请使用seq:0 + * @param limit 一次拉取的消息条数,最大值1000条,超过1000条会返回错误 + * @param proxy 使用代理的请求,需要传入代理的链接。如:socks5://10.0.0.1:8081 或者 http://10.0.0.1:8081,如果没有传null + * @param passwd 代理账号密码,需要传入代理的账号密码。如 user_name:passwd_123,如果没有传null + * @param timeout 超时时间,根据实际需要填写 + * @return 返回是否调用成功 + */ + WxCpChatDatas getChatDatas(long seq, @NonNull long limit, String proxy, String passwd, @NonNull long timeout) throws Exception; + + /** + * 获取解密的聊天数据Model + * + * @param chatData getChatDatas()获取到的聊天数据 + * @return 解密后的聊天数据 + * @throws Exception + */ + WxCpChatModel getDecryptData(@NonNull WxCpChatDatas.WxCpChatData chatData) throws Exception; + + /** + * 获取解密的聊天数据明文 + * + * @param chatData getChatDatas()获取到的聊天数据 + * @return 解密后的明文 + * @throws Exception + */ + String getChatPlainText(@NonNull WxCpChatDatas.WxCpChatData chatData) throws Exception; + + /** + * 获取媒体文件 + * 针对图片、文件等媒体数据,提供sdk接口拉取数据内容。 + * + * 注意: + * 根据上面返回的文件类型,拼接好存放文件的绝对路径即可。此时绝对路径写入文件流,来达到获取媒体文件的目的。 + * 详情可以看官方文档,亦可阅读此接口源码。 + * + * @param sdkfileid 消息体内容中的sdkfileid信息 + * @param proxy 使用代理的请求,需要传入代理的链接。如:socks5://10.0.0.1:8081 或者 http://10.0.0.1:8081,如果没有传null + * @param passwd 代理账号密码,需要传入代理的账号密码。如 user_name:passwd_123,如果没有传null + * @param timeout 超时时间,分片数据需累加到文件存储。单次最大返回512K字节,如果文件比较大,自行设置长一点,比如timeout=10000 + * @param targetFilePath 目标文件绝对路径+实际文件名,比如:/usr/local/file/20220114/474f866b39d10718810d55262af82662.gif + * @throws WxErrorException + */ + void getMediaFile(@NonNull String sdkfileid, String proxy, String passwd, @NonNull long timeout, @NonNull String targetFilePath) throws WxErrorException; + + /** + * 获取会话内容存档开启成员列表 + * 企业可通过此接口,获取企业开启会话内容存档的成员列表 + *
+ * 请求方式:POST(HTTPS) + * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/msgaudit/get_permit_user_list?access_token=ACCESS_TOKEN + * + * @param type 拉取对应版本的开启成员列表。1表示办公版;2表示服务版;3表示企业版。非必填,不填写的时候返回全量成员列表。 + * @return + * @throws WxErrorException + */ + List
getPermitUserList(Integer type) throws WxErrorException; + + /** + * 获取会话内容存档内部群信息 + * 企业可通过此接口,获取会话内容存档本企业的内部群信息,包括群名称、群主id、公告、群创建时间以及所有群成员的id与加入时间。 + * + * 请求方式:POST(HTTPS) + * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/msgaudit/groupchat/get?access_token=ACCESS_TOKEN + * + * @param roomid 待查询的群id + * @return + * @throws WxErrorException + */ + WxCpGroupChat getGroupChat(@NonNull String roomid) throws WxErrorException; + + /** + * 获取会话同意情况 + * 企业可通过下述接口,获取会话中外部成员的同意情况 + *
+ * 单聊请求地址:https://qyapi.weixin.qq.com/cgi-bin/msgaudit/check_single_agree?access_token=ACCESS_TOKEN + *
+ * 请求方式:POST(HTTPS) + * + * @param checkAgreeRequest 待查询的会话信息 + * @return + * @throws WxErrorException + */ + WxCpAgreeInfo checkSingleAgree(@NonNull WxCpCheckAgreeRequest checkAgreeRequest) 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 123697b8ed5111b8925ef4c685b9bbb8bd08a00f..a515ae1deb679a9f64167b8dcab99ac2a8117fe1 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 @@ -399,6 +399,13 @@ public interface WxCpService extends WxService { */ WxCpLivingService getLivingService(); + /** + * 获取会话存档相关接口的服务类对象 + * + * @return + */ + WxCpMsgAuditService getMsgAuditService(); + /** * 获取日历相关接口的服务类对象 * 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 210d54f54083feddd67603d2e76877e627ded623..491e562c5e0b544f85aa04ff68d6bd1e164ed54c 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 @@ -50,6 +50,7 @@ public abstract class BaseWxCpServiceImpl
implements WxCpService, RequestH private WxCpAgentService agentService = new WxCpAgentServiceImpl(this); private WxCpOaService oaService = new WxCpOaServiceImpl(this); private WxCpLivingService livingService = new WxCpLivingServiceImpl(this); + private WxCpMsgAuditService msgAuditService = new WxCpMsgAuditServiceImpl(this); private WxCpTaskCardService taskCardService = new WxCpTaskCardServiceImpl(this); private WxCpExternalContactService externalContactService = new WxCpExternalContactServiceImpl(this); private WxCpGroupRobotService groupRobotService = new WxCpGroupRobotServiceImpl(this); @@ -483,6 +484,11 @@ public abstract class BaseWxCpServiceImpl implements WxCpService, RequestH return livingService; } + @Override + public WxCpMsgAuditService getMsgAuditService() { + return msgAuditService; + } + @Override public WxCpOaCalendarService getOaCalendarService() { return this.oaCalendarService; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMsgAuditServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMsgAuditServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..6e47a4648cf5007a64f3194a2d04433f9ed3e58c --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMsgAuditServiceImpl.java @@ -0,0 +1,196 @@ +package me.chanjar.weixin.cp.api.impl; + +import com.google.gson.JsonObject; +import com.google.gson.reflect.TypeToken; +import com.tencent.wework.Finance; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.json.GsonParser; +import me.chanjar.weixin.cp.api.WxCpMsgAuditService; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.msgaudit.*; +import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; +import org.apache.commons.lang3.StringUtils; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.List; + +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.MsgAudit.*; + +/** + * 会话内容存档接口实现类. + * + * @author Wang_Wong + * @date 2022-01-17 + */ +@Slf4j +@RequiredArgsConstructor +public class WxCpMsgAuditServiceImpl implements WxCpMsgAuditService { + private final WxCpService cpService; + + @Override + public WxCpChatDatas getChatDatas(long seq, @NonNull long limit, String proxy, String passwd, @NonNull long timeout) throws Exception { + String configPath = cpService.getWxCpConfigStorage().getMsgAuditLibPath(); + if (StringUtils.isEmpty(configPath)) { + throw new WxErrorException("请配置会话存档sdk文件的路径,不要配错了!!"); + } + + // 替换斜杠 + String replacePath = configPath.replace("\\", "/"); + // 所有的后缀文件 + String suffixFiles = replacePath.substring(replacePath.lastIndexOf("/") + 1); + // 获取的前缀路径 + String prefixPath = replacePath.substring(0, replacePath.lastIndexOf("/") + 1); + + // 包含so文件 + String[] libFiles = suffixFiles.split(","); + if (libFiles.length <= 0) { + throw new WxErrorException("请仔细配置会话存档文件路径!!"); + } + + Finance.loadingLibraries(libFiles, prefixPath); + long sdk = Finance.SingletonSDK(); + + long ret = Finance.Init(sdk, cpService.getWxCpConfigStorage().getCorpId(), cpService.getWxCpConfigStorage().getCorpSecret()); + if (ret != 0) { + Finance.DestroySingletonSDK(sdk); + throw new WxErrorException("init sdk err ret " + ret); + } + + long slice = Finance.NewSlice(); + ret = Finance.GetChatData(sdk, seq, limit, proxy, passwd, timeout, slice); + if (ret != 0) { + Finance.FreeSlice(slice); + Finance.DestroySingletonSDK(sdk); + throw new WxErrorException("getchatdata err ret " + ret); + } + + // 拉取会话存档 + String content = Finance.GetContentFromSlice(slice); + Finance.FreeSlice(slice); + WxCpChatDatas chatDatas = WxCpChatDatas.fromJson(content); + if (chatDatas.getErrCode().intValue() != 0) { + throw new WxErrorException(chatDatas.toJson()); + } + + return chatDatas; + } + + @Override + public WxCpChatModel getDecryptData(@NonNull WxCpChatDatas.WxCpChatData chatData) throws Exception { + String plainText = this.decryptChatData(chatData); + return WxCpChatModel.fromJson(plainText); + } + + public String decryptChatData(WxCpChatDatas.WxCpChatData chatData) throws Exception { + // 企业获取的会话内容将用公钥加密,企业可用自行保存的私钥解开会话内容数据,aeskey不能为空 + String priKey = cpService.getWxCpConfigStorage().getAesKey(); + if (StringUtils.isEmpty(priKey)) { + throw new WxErrorException("请配置会话存档私钥【aesKey】"); + } + + String decryptByPriKey = WxCpCryptUtil.decryptByPriKey(chatData.getEncryptRandomKey(), priKey); + // 每次使用DecryptData解密会话存档前需要调用NewSlice获取一个slice,在使用完slice中数据后,还需要调用FreeSlice释放。 + long sdk = Finance.SingletonSDK(); + long msg = Finance.NewSlice(); + + int ret = Finance.DecryptData(sdk, decryptByPriKey, chatData.getEncryptChatMsg(), msg); + if (ret != 0) { + Finance.FreeSlice(msg); + Finance.DestroySingletonSDK(sdk); + throw new WxErrorException("msg err ret " + ret); + } + + // 明文 + String plainText = Finance.GetContentFromSlice(msg); + Finance.FreeSlice(msg); + return plainText; + } + + @Override + public String getChatPlainText(WxCpChatDatas.@NonNull WxCpChatData chatData) throws Exception { + return this.decryptChatData(chatData); + } + + @Override + public void getMediaFile(@NonNull String sdkfileid, String proxy, String passwd, @NonNull long timeout, @NonNull String targetFilePath) throws WxErrorException { + /** + * 1、媒体文件每次拉取的最大size为512k,因此超过512k的文件需要分片拉取。 + * 2、若该文件未拉取完整,sdk的IsMediaDataFinish接口会返回0,同时通过GetOutIndexBuf接口返回下次拉取需要传入GetMediaData的indexbuf。 + * 3、indexbuf一般格式如右侧所示,”Range:bytes=524288-1048575“:表示这次拉取的是从524288到1048575的分片。单个文件首次拉取填写的indexbuf为空字符串,拉取后续分片时直接填入上次返回的indexbuf即可。 + */ + File targetFile = new File(targetFilePath); + if (!targetFile.getParentFile().exists()) { + targetFile.getParentFile().mkdirs(); + } + + String indexbuf = ""; + int ret, data_len = 0; + while (true) { + long mediaData = Finance.NewMediaData(); + long sdk = Finance.SingletonSDK(); + ret = Finance.GetMediaData(sdk, indexbuf, sdkfileid, proxy, passwd, timeout, mediaData); + if (ret != 0) { + Finance.FreeMediaData(mediaData); + Finance.DestroySingletonSDK(sdk); + throw new WxErrorException("getmediadata err ret " + ret); + } + + data_len += Finance.GetDataLen(mediaData); + log.info("正在分片拉取媒体文件 len:{}, data_len:{}, is_finis:{} \n", Finance.GetIndexLen(mediaData), data_len, Finance.IsMediaDataFinish(mediaData)); + + try { + // 大于512k的文件会分片拉取,此处需要使用追加写,避免后面的分片覆盖之前的数据。 + FileOutputStream outputStream = new FileOutputStream(new File(targetFilePath), true); + outputStream.write(Finance.GetData(mediaData)); + outputStream.close(); + } catch (Exception e) { + e.printStackTrace(); + } + + if (Finance.IsMediaDataFinish(mediaData) == 1) { + // 已经拉取完成最后一个分片 + Finance.FreeMediaData(mediaData); + break; + } else { + // 获取下次拉取需要使用的indexbuf + indexbuf = Finance.GetOutIndexBuf(mediaData); + Finance.FreeMediaData(mediaData); + } + } + } + + @Override + public List getPermitUserList(Integer type) throws WxErrorException { + final String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(GET_PERMIT_USER_LIST); + JsonObject jsonObject = new JsonObject(); + if (type != null) { + jsonObject.addProperty("type", type); + } + String responseContent = this.cpService.post(apiUrl, jsonObject.toString()); + return WxCpGsonBuilder.create().fromJson(GsonParser.parse(responseContent).getAsJsonArray("ids"), + new TypeToken >() { + }.getType()); + } + + @Override + public WxCpGroupChat getGroupChat(@NonNull String roomid) throws WxErrorException { + final String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(GET_GROUP_CHAT); + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("roomid", roomid); + String responseContent = this.cpService.post(apiUrl, jsonObject.toString()); + return WxCpGroupChat.fromJson(responseContent); + } + + @Override + public WxCpAgreeInfo checkSingleAgree(@NonNull WxCpCheckAgreeRequest checkAgreeRequest) throws WxErrorException { + String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(CHECK_SINGLE_AGREE); + String responseContent = this.cpService.post(apiUrl, checkAgreeRequest.toJson()); + return WxCpAgreeInfo.fromJson(responseContent); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpAgreeInfo.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpAgreeInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..43a36681ed8822a287d44fe50f355c67e7356b6b --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpAgreeInfo.java @@ -0,0 +1,65 @@ +package me.chanjar.weixin.cp.bean.msgaudit; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.io.Serializable; +import java.util.List; + +/** + * 获取会话同意情况返回对象. + * + * @author Wang_Wong + */ +@Data +public class WxCpAgreeInfo implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("errcode") + private Integer errcode; + + @SerializedName("errmsg") + private String errmsg; + + @SerializedName("agreeinfo") + private List
agreeInfo; + + @Getter + @Setter + public static class AgreeInfo implements Serializable { + private static final long serialVersionUID = -5696099236344075582L; + + @SerializedName("status_change_time") + private Long statusChangeTime; + + @SerializedName("userid") + private String userid; + + @SerializedName("exteranalopenid") + private String exteranalOpenId; + + @SerializedName("agree_status") + private String agreeStatus; + + public static AgreeInfo fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, AgreeInfo.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + public static WxCpAgreeInfo fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpAgreeInfo.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpChatDatas.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpChatDatas.java new file mode 100644 index 0000000000000000000000000000000000000000..8359bc087d11197899dd0631d2feec45b628c41f --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpChatDatas.java @@ -0,0 +1,68 @@ +package me.chanjar.weixin.cp.bean.msgaudit; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.io.Serializable; +import java.util.List; + +/** + * 聊天记录数据内容. + * + * @author Wang_Wong + */ +@Data +public class WxCpChatDatas implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("errcode") + private Integer errCode; + + @SerializedName("errmsg") + private String errMsg; + + @SerializedName("chatdata") + private List chatData; + + @Getter + @Setter + public static class WxCpChatData implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("seq") + private Long seq; + + @SerializedName("msgid") + private String msgId; + + @SerializedName("publickey_ver") + private Integer publickeyVer; + + @SerializedName("encrypt_random_key") + private String encryptRandomKey; + + @SerializedName("encrypt_chat_msg") + private String encryptChatMsg; + + public static WxCpChatData fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpChatData.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + public static WxCpChatDatas fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpChatDatas.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpChatModel.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpChatModel.java new file mode 100644 index 0000000000000000000000000000000000000000..888f7f399c1839f22c0a0208dc8469e1b8e17477 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpChatModel.java @@ -0,0 +1,987 @@ +package me.chanjar.weixin.cp.bean.msgaudit; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.io.Serializable; +import java.util.List; + +/** + * 聊天记录数据内容. + * + * @author Wang_Wong + */ +@Data +public class WxCpChatModel implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("msgid") + private String msgId; + + @SerializedName("action") + private String action; + + @SerializedName("send") + private String send; + + @SerializedName("from") + private String from; + + @SerializedName("tolist") + private String[] tolist; + + @SerializedName("roomid") + private String roomId; + + @SerializedName("msgtime") + private Long msgTime; + + @SerializedName("msgtype") + private String msgType; + + /** + * 文本 + */ + @SerializedName("text") + private Text text; + + /** + * 图片 + */ + @SerializedName("image") + private Image image; + + /** + * 撤回消息 + */ + @SerializedName("revoke") + private Revoke revoke; + + /** + * 同意会话聊天内容 + */ + @SerializedName(value = "agree") + private Agree agree; + + @SerializedName(value = "disagree") + private Agree disagree; + + /** + * 语音 + */ + @SerializedName(value = "voice") + private Voice voice; + + /** + * 视频 + */ + @SerializedName(value = "video") + private Video video; + + /** + * 名片 + */ + @SerializedName(value = "card") + private Card card; + + /** + * 位置 + */ + @SerializedName(value = "location") + private Location location; + + /** + * 表情 + */ + @SerializedName(value = "emotion") + private Emotion emotion; + + /** + * 文件 + */ + @SerializedName(value = "file") + private File file; + + /** + * 链接 + */ + @SerializedName(value = "link") + private Link link; + + /** + * 小程序消息 + */ + @SerializedName(value = "weapp") + private Weapp weapp; + + /** + * 会话记录消息 + */ + @SerializedName(value = "chatrecord") + private ChatRecord chatRecord; + + /** + * 待办消息 官网暂无 + */ + + /** + * 投票消息 官网暂无 + */ + + /** + * 填表消息 + */ + @SerializedName(value = "collect") + private Collect collect; + + /** + * 红包消息 + * 互通红包消息 + */ + @SerializedName("redpacket") + private Redpacket redPacket; + + /** + * 会议邀请消息 + */ + @SerializedName("meeting") + private Meeting meeting; + + /** + * 切换企业日志 + */ + @SerializedName("time") + private Long time; + + @SerializedName("user") + private String user; + + /** + * 在线文档消息 + */ + @SerializedName("doc") + private Doc doc; + + @SerializedName("info") + private Info info; + + /** + * 日程消息 + */ + @SerializedName("calendar") + private Calendar calendar; + + /** + * 混合消息 + */ + @SerializedName("mixed") + private Mixed mixed; + + /** + * 音频存档消息 + */ + @SerializedName("voiceid") + private String voiceId; + + @SerializedName("meeting_voice_call") + private MeetingVoiceCall meetingVoiceCall; + + /** + * 音频共享文档消息 + */ + @SerializedName("voipid") + private String voipId; + + @SerializedName("voip_doc_share") + private WxCpFileItem voipDocShare; + + /** + * 视频号消息 + */ + @SerializedName("sphfeed") + private SphFeed sphFeed; + + public static WxCpChatModel fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpChatModel.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + + @Getter + @Setter + public static class Text implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("content") + private String content; + + public static Text fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, Text.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + + @Getter + @Setter + public static class Image implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("md5sum") + private String md5Sum; + + @SerializedName("sdkfileid") + private String sdkFileId; + + @SerializedName("filesize") + private Long fileSize; + + public static Image fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, Image.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + + @Getter + @Setter + public static class Revoke implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("pre_msgid") + private String preMsgId; + + public static Revoke fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, Revoke.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + + @Getter + @Setter + public static class Agree implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("userid") + private String userId; + + @SerializedName(value = "agree_time") + private Long agreeTime; + + @SerializedName(value = "disagree_time") + private Long disagreeTime; + + public static Agree fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, Agree.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + + @Getter + @Setter + public static class Voice implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("md5sum") + private String md5Sum; + + @SerializedName("sdkfileid") + private String sdkFileId; + + @SerializedName("voice_size") + private Long voiceSize; + + @SerializedName("play_length") + private Long playLength; + + public static Voice fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, Voice.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + + @Getter + @Setter + public static class Video implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("md5sum") + private String md5Sum; + + @SerializedName("sdkfileid") + private String sdkFileId; + + @SerializedName("filesize") + private Long fileSize; + + @SerializedName("play_length") + private Long playLength; + + public static Video fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, Video.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + + @Getter + @Setter + public static class Card implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("corpname") + private String corpName; + + @SerializedName("userid") + private String userId; + + public static Card fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, Card.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + + @Getter + @Setter + public static class Location implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("longitude") + private Double longitude; + + @SerializedName("latitude") + private Double latitude; + + @SerializedName("address") + private String address; + + @SerializedName("title") + private String title; + + @SerializedName("zoom") + private Integer zoom; + + public static Location fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, Location.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + + @Getter + @Setter + public static class Emotion implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("type") + private Integer type; + + @SerializedName("width") + private Integer width; + + @SerializedName("height") + private Integer height; + + @SerializedName("title") + private String title; + + @SerializedName("imagesize") + private Integer imageSize; + + @SerializedName("md5sum") + private String md5Sum; + + @SerializedName("sdkfileid") + private String sdkFileId; + + public static Emotion fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, Emotion.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + + @Getter + @Setter + public static class File implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("md5sum") + private String md5Sum; + + @SerializedName("filename") + private String fileName; + + @SerializedName("fileext") + private String fileExt; + + @SerializedName("sdkfileid") + private String sdkFileId; + + @SerializedName("filesize") + private Integer fileSize; + + public static File fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, File.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + + @Getter + @Setter + public static class Link implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("title") + private String title; + + @SerializedName("description") + private String description; + + @SerializedName("link_url") + private String linkUrl; + + @SerializedName("image_url") + private String imageUrl; + + public static Link fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, Link.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + + /** + * 小程序消息 + */ + @Getter + @Setter + public static class Weapp implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("title") + private String title; + + @SerializedName("description") + private String description; + + @SerializedName("username") + private String userName; + + @SerializedName("displayname") + private String displayName; + + public static Weapp fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, Weapp.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + + /** + * 会话记录消息 + */ + @Getter + @Setter + public static class ChatRecord implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName(value = "item") + private List item; + + @SerializedName("title") + private String title; + + public static ChatRecord fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, ChatRecord.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + + @Getter + @Setter + public static class ChatRecordItem implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("type") + private String type; + + @SerializedName("msgtime") + private Long msgTime; + + @SerializedName("content") + private String content; + + @SerializedName("from_chatroom") + private Boolean fromChatRoom; + + public static ChatRecordItem fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, ChatRecordItem.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + + /** + * 填表消息 + */ + @Getter + @Setter + public static class Collect implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("room_name") + private String roomName; + + @SerializedName("creator") + private String creator; + + @SerializedName("create_time") + private String createTime; + + @SerializedName("title") + private String title; + + @SerializedName("details") + private List details; + + public static Collect fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, Collect.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + + @Getter + @Setter + public static class Details implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("id") + private Long id; + + @SerializedName("ques") + private String ques; + + @SerializedName("type") + private String type; + + public static Details fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, Details.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + + /** + * 红包消息 + */ + @Getter + @Setter + public static class Redpacket implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("type") + private Integer type; + + @SerializedName("totalcnt") + private Integer totalCnt; + + @SerializedName("totalamount") + private Integer totalAmount; + + @SerializedName("wish") + private String wish; + + public static Redpacket fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, Redpacket.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + + /** + * 会议邀请消息 + */ + @Getter + @Setter + public static class Meeting implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("topic") + private String topic; + + @SerializedName("starttime") + private Long startTime; + + @SerializedName("endtime") + private Long endTime; + + @SerializedName("address") + private String address; + + @SerializedName("remarks") + private String remarks; + + @SerializedName("meetingtype") + private Integer meetingType; + + @SerializedName("meetingid") + private Long meetingId; + + @SerializedName("status") + private Integer status; + + public static Meeting fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, Meeting.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + + /** + * 在线文档消息 + */ + @Getter + @Setter + public static class Doc implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("title") + private String title; + + @SerializedName("doc_creator") + private String docCreator; + + @SerializedName("link_url") + private String linkUrl; + + public static Doc fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, Doc.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + + /** + * MarkDown格式消息 + */ + @Getter + @Setter + public static class Info implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("content") + private String content; + + @SerializedName("item") + private ListnewsItem; + + public static Info fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, Info.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + + /** + * 图文消息 + */ + @Getter + @Setter + public static class NewsItem implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("title") + private String title; + + @SerializedName("description") + private String description; + + @SerializedName("url") + private String url; + + @SerializedName("picurl") + private String picUrl; + + public static NewsItem fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, NewsItem.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + + /** + * 日程消息 + */ + @Getter + @Setter + public static class Calendar implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("title") + private String title; + + @SerializedName("creatorname") + private String creatorName; + + @SerializedName("attendeename") + private String[] attendeeName; + + @SerializedName("starttime") + private Long startTime; + + @SerializedName("endtime") + private Long endTime; + + @SerializedName("place") + private String place; + + @SerializedName("remarks") + private String remarks; + + public static Calendar fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, Calendar.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + + /** + * 混合消息 + */ + @Getter + @Setter + public static class Mixed implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("item") + private List - item; + + @Getter + @Setter + public static class Item implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("type") + private String type; + + @SerializedName("content") + private String content; + + } + + } + + + /** + * 音频存档消息 + */ + @Getter + @Setter + public static class MeetingVoiceCall implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("endtime") + private Long endTime; + + @SerializedName("sdkfileid") + private String sdkFileId; + + @SerializedName("demofiledata") + private List
demoFileData; + + @SerializedName("sharescreendata") + private List shareScreenData; + + public static MeetingVoiceCall fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, MeetingVoiceCall.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + @Getter + @Setter + public static class DemoFileData implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("filename") + private String fileName; + + @SerializedName("demooperator") + private String demoOperator; + + @SerializedName("starttime") + private Long startTime; + + @SerializedName("endtime") + private Long endTime; + + public static DemoFileData fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, DemoFileData.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + @Getter + @Setter + public static class ShareScreenData implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("share") + private String share; + + @SerializedName("starttime") + private Long startTime; + + @SerializedName("endtime") + private Long endTime; + + public static ShareScreenData fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, ShareScreenData.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + } + + + /** + * 视频号消息 + */ + @Getter + @Setter + public static class SphFeed implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("feed_type") + private Integer feedType; + + @SerializedName("sph_name") + private String sphName; + + @SerializedName("feed_desc") + private String feedDesc; + + public static SphFeed fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, SphFeed.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpCheckAgreeRequest.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpCheckAgreeRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..83d1b18127dfd3936a0a4ca28d8648184a641c86 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpCheckAgreeRequest.java @@ -0,0 +1,57 @@ +package me.chanjar.weixin.cp.bean.msgaudit; + +import com.google.gson.annotations.SerializedName; +import lombok.*; +import lombok.experimental.Accessors; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.io.Serializable; +import java.util.List; + +/** + * 获取会话同意情况请求参数. + * + * @author Wang_Wong + * @date 2022-01-21 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Accessors(chain = true) +public class WxCpCheckAgreeRequest implements Serializable { + private static final long serialVersionUID = -4960239393895754138L; + + @SerializedName("info") + private List info; + + public static WxCpCheckAgreeRequest fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpCheckAgreeRequest.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + @Getter + @Setter + public static class Info implements Serializable { + private static final long serialVersionUID = -4960239393895754138L; + + @SerializedName("userid") + private String userid; + + @SerializedName("exteranalopenid") + private String exteranalOpenId; + + public static Info fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, Info.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpFileItem.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpFileItem.java new file mode 100644 index 0000000000000000000000000000000000000000..7b7be15c5fa7b2c0e00d79e86872933b0c208674 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpFileItem.java @@ -0,0 +1,39 @@ +package me.chanjar.weixin.cp.bean.msgaudit; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.io.Serializable; + +/** + * 会话存档 文档信息对象 + * + * @author Wang_Wong + */ +@Data +public class WxCpFileItem implements Serializable { + + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("filename") + private String fileName; + + @SerializedName("md5sum") + private String md5Sum; + + @SerializedName("sdkfileid") + private String sdkFileId; + + @SerializedName("filesize") + private Long fileSize; + + public static WxCpFileItem fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpFileItem.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpGroupChat.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpGroupChat.java new file mode 100644 index 0000000000000000000000000000000000000000..3a2656bfb03db80feec295648c9a9ac40388974c --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpGroupChat.java @@ -0,0 +1,61 @@ +package me.chanjar.weixin.cp.bean.msgaudit; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.io.Serializable; +import java.util.List; + +/** + * 内部群信息 + * + * @author Wang_Wong + */ +@Data +public class WxCpGroupChat implements Serializable { + + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("roomname") + private String roomName; + + @SerializedName("creator") + private String creator; + + @SerializedName("room_create_time") + private Long roomCreateTime; + + @SerializedName("notice") + private String notice; + + private List members; + + @Getter + @Setter + public class Member implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("memberid") + private String memberId; + + @SerializedName("jointime") + private Long joinTime; + + public Member fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, Member.class); + } + + } + + public static WxCpGroupChat fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpGroupChat.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + +} 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 02a7af880ef65f724be1f3bcac12fe2a5285a4e6..1d7e9685d0566f42323d42f03f47bbbfc5f985f1 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 @@ -174,6 +174,13 @@ public interface WxCpConfigStorage { */ String getAesKey(); + /** + * 获取企微会话存档系统库 绝对路径 + * + * @return + */ + String getMsgAuditLibPath(); + /** * Gets expires time. * diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpDefaultConfigImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpDefaultConfigImpl.java index 0fbf61724dc9a7a7f7480ba6b69a3f8d29e08c88..b7304628a7d0d712563e0f2c9a0a0d0d0109622a 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpDefaultConfigImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpDefaultConfigImpl.java @@ -43,6 +43,7 @@ public class WxCpDefaultConfigImpl implements WxCpConfigStorage, Serializable { private volatile String token; private volatile String aesKey; private volatile long expiresTime; + private volatile String msgAuditLibPath; private volatile String oauth2redirectUri; private volatile String httpProxyHost; private volatile int httpProxyPort; @@ -256,6 +257,11 @@ public class WxCpDefaultConfigImpl implements WxCpConfigStorage, Serializable { return this.aesKey; } + @Override + public String getMsgAuditLibPath() { + return this.msgAuditLibPath; + } + /** * Sets aes key. * diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpRedisConfigImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpRedisConfigImpl.java index 027ab825c7dd0dc4e155b5ab30de52a7778a2083..89b939e6131c124abd8fe668b71145265cb214e4 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpRedisConfigImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpRedisConfigImpl.java @@ -40,6 +40,7 @@ public class WxCpRedisConfigImpl implements WxCpConfigStorage { private volatile String token; private volatile String aesKey; private volatile Integer agentId; + private volatile String msgAuditLibPath; private volatile String oauth2redirectUri; private volatile String httpProxyHost; private volatile int httpProxyPort; @@ -320,6 +321,11 @@ public class WxCpRedisConfigImpl implements WxCpConfigStorage { return this.aesKey; } + @Override + public String getMsgAuditLibPath() { + return this.msgAuditLibPath; + } + /** * Sets aes key. * 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 cea1bcb9baa49055b20ad9bc09540e6a5c45de83..4ec43661135fed33ddd06ac68bb2d43c62212565 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 @@ -129,6 +129,12 @@ public interface WxCpApiPathConsts { String DELETE_REPLAY_DATA = "/cgi-bin/living/delete_replay_data"; } + interface MsgAudit { + String GET_PERMIT_USER_LIST = "/cgi-bin/msgaudit/get_permit_user_list"; + String GET_GROUP_CHAT = "/cgi-bin/msgaudit/groupchat/get"; + String CHECK_SINGLE_AGREE = "/cgi-bin/msgaudit/check_single_agree"; + } + interface Tag { String TAG_CREATE = "/cgi-bin/tag/create"; String TAG_UPDATE = "/cgi-bin/tag/update"; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpCryptUtil.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpCryptUtil.java index 2914945b895f68abe799252d51e15a8ad3709a9e..d36a1ce342e583573f5a8a87fe35f2311ed051c9 100755 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpCryptUtil.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpCryptUtil.java @@ -4,6 +4,12 @@ import com.google.common.base.CharMatcher; import com.google.common.io.BaseEncoding; import me.chanjar.weixin.common.util.crypto.WxCryptUtil; import me.chanjar.weixin.cp.config.WxCpConfigStorage; +import org.apache.commons.codec.binary.Base64; + +import javax.crypto.Cipher; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.spec.PKCS8EncodedKeySpec; public class WxCpCryptUtil extends WxCryptUtil { public WxCpCryptUtil(WxCpConfigStorage wxCpConfigStorage) { @@ -21,4 +27,31 @@ public class WxCpCryptUtil extends WxCryptUtil { this.aesKey = BaseEncoding.base64().decode(CharMatcher.whitespace().removeFrom(encodingAesKey)); } + /** + * 会话存档接口解密私钥 + * 企业获取的会话内容将用公钥加密,企业用自行保存的私钥解开会话内容数据 + * + * @param encryptRandomKey + * @param msgAuditPriKey + * @return + * @throws Exception + */ + public static String decryptByPriKey(String encryptRandomKey, String msgAuditPriKey) throws Exception { + String privateKey = msgAuditPriKey.replaceAll("\\n", "") + .replace("-----BEGIN PRIVATE KEY-----", "") + .replace("-----END PRIVATE KEY-----", "") + .replaceAll(" ", ""); + + byte[] keyByte = Base64.decodeBase64(privateKey); + PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyByte); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec); + + Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); + cipher.init(Cipher.DECRYPT_MODE, priKey); + byte[] utf8 = cipher.doFinal(Base64.decodeBase64(encryptRandomKey)); + + return new String(utf8, "UTF-8"); + } + } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMsgAuditTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMsgAuditTest.java new file mode 100644 index 0000000000000000000000000000000000000000..457996a0e42164a4f72ef309e30fbb67c8e135a1 --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMsgAuditTest.java @@ -0,0 +1,433 @@ +package me.chanjar.weixin.cp.api; +import com.google.common.collect.Lists; + +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; +import me.chanjar.weixin.cp.bean.msgaudit.*; +import me.chanjar.weixin.cp.config.WxCpConfigStorage; +import me.chanjar.weixin.cp.demo.WxCpDemoInMemoryConfigStorage; +import org.testng.annotations.Test; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +/** + * 企业微信会话内容存档测试类. + * 官方文档:https://developer.work.weixin.qq.com/document/path/91360 + * + * @author Wang_Wong + * @date 2022-01-17 + */ +@Slf4j +public class WxCpMsgAuditTest { + + private static WxCpConfigStorage wxCpConfigStorage; + private static WxCpService cpService; + + // com.binarywang.spring.starter.wxjava.cp.config.WxCpServiceAutoConfiguration + @Test + public void test() throws Exception { + + InputStream inputStream = ClassLoader.getSystemResourceAsStream("test-config.xml"); + WxCpDemoInMemoryConfigStorage config = WxCpDemoInMemoryConfigStorage.fromXml(inputStream); + + wxCpConfigStorage = config; + cpService = new WxCpServiceImpl(); + cpService.setWxCpConfigStorage(config); + + /** + * 配置: + * + * + */ + + /** + * 建议放到redis,本次请求获取消息记录开始的seq值。首次访问填写0,非首次使用上次企业微信返回的最大seq。允许从任意seq重入拉取。 + */ + long seq = 0L; + + /** + * 图片,语音,视频,表情,文件,音频存档消息,音频共享文档消息调用 获取媒体消息 + */ + Listwwa3bexxXXXXXX + *自定义agentId + *xIpum7Yt4NMXXXXXXX + *2bSNqXXXXXXXX + *MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZuPVMyVyMvJkdSCZA893B2pggd1r95T8k2QZgz+VejtaDJCbD60mYoW1Uwwlwuqy8W78M6MmXsskn+5XunyR1WJlJGqgi0OMVGYvSfkNb9kD50fM21CGLcN1y4miL9fVNBIsvJmIUeJCNS8TioAVGFvh2EgzjqTR1gHfDwu8If7rfGmTHkPYL8hQxMg/EQ3451JOIBHSa7EQSx64SIoVWEgSDFQjGEpjUiJRfciyyz+nTSkEDgFa9hpyTS6E0c/3Q5lVDFgIwTArC19XBFKb00PbcFuLriOIsTBX4K9XWBtefVXowAdqUVQDH6BNUIK7/iVPQ4L3p+F5DBOrx8I/7AgMBAAECggEBAK53C/nwEX2lU3ynaB/8SuMga274ta1mmmbIkdfaQA65nyOPQJEWZe8szBN0BoiSzgBR9JI/p+srlQ25CLgiRnDSAmMWPU1I3e72fZi7HPcAKakGmEKDUi4OzyVUUDp3aY3B6lZqB4Yn5o2S/b4sRI2ZspfKdxGncSYHP/Far3i6hzq2C1hbyYM6HkHPcrQ+z6ir6GxjLvHXssVJ+/C0HMsVIQAWPyEGbzWozS+EswmQ+itk+7cewiLWbaCSp6lsjHKGTxJwCxRes0nUt2SfkLnIUkDLxB7c6zDQJCn1K2UckCjNBlCWl+oDWLkLQ7UAJ+4IYYSslR4wXzRg8PplW8ECgYEA9VlEprEoG2oSn3HXIMFg0MANViQe89QJQdwd7D5h4FLxXQLItxqmZj77iktlzlICcK9WT9WHRY1AOilsuMaDmY0VH3Z8r/X9BU712KFJqMYH5CNxrqHOya3BG+CclEKToaOTmo9kiOpFAMNSuuWs6gvILJ0CKEmSUo5G9fJu4fkCgYEA4yypHoRZIP0mDdVDeVtdHHcq5JdWF6xbAFs4P57VHG1KDMWouk3IHSeO279gEIwcBAdaLcMMgFfzyQBwcisxjC76oyoZnbSntB7ZMFdPqALKfxIdleLilbASuRKesVAF+OgOx/yp/aQUeLG2pVBivgn2TyGMwjnxznTh9vh+vpMCgYEAmOva7krdRLkIgnjiLXhab8JEjbxVzoQKgRJBVE5NkxQffGmP0RC7Rl9bSQdVnRNgkfu3QGtGtQMlVRscuM6Cl+JnmASyErqvye89LJja4GcN5BRzdvVDflDeXBHThlU4zza1eVCGyQ+7ko4rsnIVJIvTaHs0LQguO2aStBk3I4ECgYAyBsO3VK3L9fNLWItjThtTCWsIq8rpq6reiTf5yqBjgi2sYlqlrDtFMFDlU190RWZl/Lh/G1TFbpjgypf4jEp89Ft9UugRMpc7sw9g9dk0xmiRUwvw1eXP0NZOqysHIPgvt+qJX7qPgHKBoaD3Bpy3/Lmg82Jr4xa8wECCgnZmwQKBgH7hirPs1/HqBrbxS726IZUf9QTmVkyOYIwzuwFYKb/+4caSah+iaXexVux0xS5tchj/6c1dQSKJmlegV8smIb6EEcko7llA1y1P5QFtXtaaRd07tTsv3BKEg496YLRjbxPzgJn6Fsoz3TTdGwESL8Q3I2h0WmVVhmr/rjr+RkWQ + * + * 注意:最好先配置lib开头的系统库,再配置sdk类库,配置绝对路径,最好配置为linux路径 + * windows: + *D:/WorkSpace/libcrypto-1_1-x64.dll,libssl-1_1-x64.dll,libcurl-x64.dll,WeWorkFinanceSdk.dll,libWeWorkFinanceSdk_Java.so + * linux: + */www/osfile/work_msg_storage/libcrypto-1_1-x64.dll,libssl-1_1-x64.dll,libcurl-x64.dll,WeWorkFinanceSdk.dll,libWeWorkFinanceSdk_Java.so + *mediaType = Arrays.asList(new String[]{"image", "voice", "video", "emotion", "file", "meeting_voice_call", "voip_doc_share"}); + + // 模拟多次拉取数据,根据seq拉取 + for (int i = 0; i < 3; i++) { + // 本次请求获取消息记录开始的seq值。首次访问填写0,非首次使用上次企业微信返回的最大seq。允许从任意seq重入拉取。 + WxCpChatDatas chatDatas = cpService.getMsgAuditService().getChatDatas(seq, 10L, null, null, 1000L); + if (chatDatas != null && chatDatas.getChatData().size() > 0) { + + List chatdata = chatDatas.getChatData(); + Iterator iterator = chatdata.iterator(); + while (iterator.hasNext()) { + WxCpChatDatas.WxCpChatData chatData = iterator.next(); + seq = chatData.getSeq(); + + // 数据 +// String msgId = chatData.getMsgId(); +// String encryptChatMsg = chatData.getEncryptChatMsg(); +// String encryptRandomKey = chatData.getEncryptRandomKey(); +// Integer publickeyVer = chatData.getPublickeyVer(); + + // 获取明文数据 + final String chatPlainText = cpService.getMsgAuditService().getChatPlainText(chatData); + final WxCpChatModel wxCpChatModel = WxCpChatModel.fromJson(chatPlainText); + log.info("明文数据为:{}", wxCpChatModel.toJson()); + + // 获取消息数据 + final WxCpChatModel decryptData = cpService.getMsgAuditService().getDecryptData(chatData); + log.info("获取消息数据为:{}", decryptData.toJson()); + + /** + * 注意: + * 根据上面返回的文件类型来获取媒体文件, + * 不同的文件类型,拼接好存放文件的绝对路径,写入文件流,获取媒体文件。(拼接绝对文件路径的原因,以便上传到腾讯云或阿里云对象存储) + * + * 目标文件绝对路径+实际文件名,比如:/usr/local/file/20220114/474f866b39d10718810d55262af82662.gif + */ + String path = "/usr/local/file/"; + String msgType = decryptData.getMsgType(); + if (mediaType.contains(decryptData.getMsgType())) { + // 文件后缀 + String suffix = ""; + // 文件名md5 + String md5Sum = ""; + // sdkFileId + String sdkFileId = ""; + switch (msgType) { + case "image": + suffix = ".jpg"; + md5Sum = decryptData.getImage().getMd5Sum(); + sdkFileId = decryptData.getImage().getSdkFileId(); + break; + case "voice": + suffix = ".amr"; + md5Sum = decryptData.getVoice().getMd5Sum(); + sdkFileId = decryptData.getVoice().getSdkFileId(); + break; + case "video": + suffix = ".mp4"; + md5Sum = decryptData.getVideo().getMd5Sum(); + sdkFileId = decryptData.getVideo().getSdkFileId(); + break; + case "emotion": + md5Sum = decryptData.getEmotion().getMd5Sum(); + sdkFileId = decryptData.getEmotion().getSdkFileId(); + int type = decryptData.getEmotion().getType(); + switch (type) { + case 1: + suffix = ".gif"; + break; + case 2: + suffix = ".png"; + break; + default: + return; + } + break; + case "file": + md5Sum = decryptData.getFile().getMd5Sum(); + suffix = "." + decryptData.getFile().getFileExt(); + sdkFileId = decryptData.getFile().getSdkFileId(); + break; + // 音频存档消息 + case "meeting_voice_call": + + md5Sum = decryptData.getVoiceId(); + sdkFileId = decryptData.getMeetingVoiceCall().getSdkFileId(); + for (WxCpChatModel.MeetingVoiceCall.DemoFileData demofiledata : decryptData.getMeetingVoiceCall().getDemoFileData()) { + String demoFileDataFileName = demofiledata.getFileName(); + suffix = demoFileDataFileName.substring(demoFileDataFileName.lastIndexOf(".") + 1); + } + + break; + // 音频共享文档消息 + case "voip_doc_share": + + md5Sum = decryptData.getVoipId(); + WxCpFileItem docShare = decryptData.getVoipDocShare(); + String fileName = docShare.getFileName(); + suffix = fileName.substring(fileName.lastIndexOf(".") + 1); + + break; + default: + return; + } + + // 拉取媒体文件 + String targetPath = path + md5Sum + suffix; + cpService.getMsgAuditService().getMediaFile(sdkFileId, null, null, 1000L, targetPath); + + } + + } + + } + + } + + + /** + * 文本 + */ +// String text = "{\"msgid\":\"CAQQluDa4QUY0On2rYSAgAMgzPrShAE=\",\"action\":\"send\",\"from\":\"XuJinSheng\",\"tolist\":[\"icefog\"],\"roomid\":\"\",\"msgtime\":1547087894783,\"msgtype\":\"text\",\"text\":{\"content\":\"test\"}}"; + String text = "{\"msgid\":\"CAQQluDa4QUY0On2rYSAgAMgzPrShAE=\",\"action\":\"send\",\"from\":\"XuJinSheng\",\"tolist\":[\"icefog\"],\"roomid\":\"\",\"msgtime\":1547087894783,\"msgtype\":\"text\",\"text\":{\"content\":\"这是一条引用/回复消息:\\\"\\n------\\n@nick777\"}}"; + WxCpChatModel modelText = WxCpChatModel.fromJson(text); + log.info("数据为:" + modelText.toJson()); + + + /** + * 图片 + */ + String image = "{\"msgid\":\"CAQQvPnc4QUY0On2rYSAgAMgooLa0Q8=\",\"action\":\"send\",\"from\":\"XuJinSheng\",\"tolist\":[\"icefog\"],\"roomid\":\"\",\"msgtime\":0,\"msgtype\":\"image\",\"image\":{\"md5sum\":\"50de8e5ae8ffe4f1df7a93841f71993a\",\"filesize\":70961,\"sdkfileid\":\"CtYBMzA2OTAyMDEwMjA0NjIzMDYwMDIwMTAwMDIwNGI3ZmU0MDZlMDIwMzBmNTliMTAyMDQ1YzliNTQ3NzAyMDQ1YzM3M2NiYzA0MjQ2NjM0MzgzNTM0NjEzNTY1MmQzNDYxMzQzODJkMzQzMTYxNjEyZDM5NjEzOTM2MmQ2MTM2NjQ2NDY0NjUzMDY2NjE2NjM1MzcwMjAxMDAwMjAzMDExNTQwMDQxMDUwZGU4ZTVhZThmZmU0ZjFkZjdhOTM4NDFmNzE5OTNhMDIwMTAyMDIwMTAwMDQwMBI4TkRkZk1UWTRPRGcxTVRBek1ETXlORFF6TWw4eE9UUTVOamN6TkRZMlh6RTFORGN4TWpNNU1ERT0aIGEwNGQwYWUyM2JlYzQ3NzQ5MjZhNWZjMjk0ZTEyNTkz\"}}"; + WxCpChatModel modelImage = WxCpChatModel.fromJson(image); + log.info("数据为:" + modelImage.toJson()); + + + /** + * 撤回消息 + */ + String revoke = "{\"msgid\":\"15775510700152506326_1603875615\",\"action\":\"recall\",\"from\":\"kenshin\",\"tolist\":[\"wmUu0zBgAALV7ZymkcMyxvbTe8YdWxxA\"],\"roomid\":\"\",\"msgtime\":1603875615723,\"msgtype\":\"revoke\",\"revoke\":{\"pre_msgid\":\"14822339130656386894_1603875600\"}}"; + WxCpChatModel modelRevoke = WxCpChatModel.fromJson(revoke); + log.info("数据为:" + modelRevoke.toJson()); + + + /** + * 同意会话聊天内容 + */ + String agree = "{\"msgid\":\"8891446340739254950_1603875826\",\"action\":\"send\",\"from\":\"wmGAgeDQAAvQeaTqWwkMTxGMkvI7OOuQ\",\"tolist\":[\"kenshin\"],\"roomid\":\"\",\"msgtime\":1603875826656,\"msgtype\":\"agree\",\"agree\":{\"userid\":\"wmGAgeDQAAvQeaTqWwkMTxGMkvI7OOuQ\",\"agree_time\":1603875826656}}"; + String disagree = "{\"msgid\":\"17972321270926900092_1603875944\",\"action\":\"send\",\"from\":\"wmErxtDgAA9AW32YyyuYRimKr7D1KWlw\",\"tolist\":[\"kenshin\"],\"roomid\":\"\",\"msgtime\":1603875944122,\"msgtype\":\"disagree\",\"disagree\":{\"userid\":\"wmErxtDgAA9AW32YyyuYRimKr7D1KWlw\",\"disagree_time\":1603875944122}}"; + WxCpChatModel modelAgree = WxCpChatModel.fromJson(agree); + WxCpChatModel modelDisagree = WxCpChatModel.fromJson(disagree); + log.info("数据为:" + modelAgree.toJson()); + log.info("数据为:" + modelDisagree.toJson()); + + + /** + * 语音 + */ + String voice = "{\"msgid\":\"10958372969718811103_1603875609\",\"action\":\"send\",\"from\":\"wmGAgeDQAAdBjb8CK4ieMPRm7Cqm-9VA\",\"tolist\":[\"kenshin\"],\"roomid\":\"\",\"msgtime\":1603875609704,\"msgtype\":\"voice\",\"voice\":{\"md5sum\":\"9db09c7fa627c9e53f17736c786a74d5\",\"voice_size\":6810,\"play_length\":10,\"sdkfileid\":\"kcyZjZqOXhETGYxajB2Zkp5Rk8zYzh4RVF3ZzZGdXlXNWRjMUoxVGZxbzFTTDJnQ2YxL0NraVcxUUJNK3VUamhEVGxtNklCbjZmMEEwSGRwN0h2cU1GQTU1MDRSMWdTSmN3b25ZMkFOeG5hMS90Y3hTQ0VXRlVxYkR0Ymt5c3JmV2VVcGt6UlNXR1ZuTFRWVGtudXVldDRjQ3hscDBrMmNhMFFXVnAwT3Y5NGVqVGpOcWNQV2wrbUJwV01TRm9xWmNDRVVrcFY5Nk9OUS9GbXIvSmZvOVVZZjYxUXBkWnMvUENkVFQxTHc2N0drb2pJT0FLZnhVekRKZ1FSNDU3ZnZtdmYvTzZDOG9DRXl2SUNIOHc9PRI0TkRkZk56ZzRNVE13TVRjMk5qQTRNak0yTmw4ek5qRTVOalExTjE4eE5qQXpPRGMxTmpBNRogNzM3MDY2NmM2YTc5Njg3NDdhNzU3NDY0NzY3NTY4NjY=\"}}"; + WxCpChatModel modelVoice = WxCpChatModel.fromJson(voice); + log.info("数据为:" + modelVoice.toJson()); + + + /** + * 视频 + */ + String video = "{\"msgid\":\"17955920891003447432_1603875627\",\"action\":\"send\",\"from\":\"kenshin\",\"tolist\":[\"wmGAgeDQAAHuRJbt4ZQI_1cqoQcf41WQ\"],\"roomid\":\"\",\"msgtime\":1603875626823,\"msgtype\":\"video\",\"video\":{\"md5sum\":\"d06fc80c01d6fbffcca3b229ba41eac6\",\"filesize\":15169724,\"play_length\":108,\"sdkfileid\":\"MzAzMjYxMzAzNTYzMzgzMjMyMzQwMjAxMDAwMjA0MDBlNzc4YzAwNDEwZDA2ZmM4MGMwMWQ2ZmJmZmNjYTNiMjI5YmE0MWVhYzYwMjAxMDQwMjAxMDAwNDAwEjhORGRmTVRZNE9EZzFNREEyTlRjM056QXpORjgxTWpZeE9USTBOek5mTVRZd016ZzNOVFl5Tnc9PRogNTIzNGQ1NTQ5N2RhNDM1ZDhlZTU5ODk4NDQ4NzRhNDk=\"}}"; + WxCpChatModel modelVideo = WxCpChatModel.fromJson(video); + log.info("数据为:" + modelVideo.toJson()); + + + /** + * 名片 + */ + String card = "{\"msgid\":\"13714216591700685558_1603875680\",\"action\":\"send\",\"from\":\"kenshin\",\"tolist\":[\"wmGAgeDQAAy2Dtr0F8aK4dTuatfm-5Rg\"],\"roomid\":\"\",\"msgtime\":1603875680377,\"msgtype\":\"card\",\"card\":{\"corpname\":\"微信联系人\",\"userid\":\"wmGAgeDQAAGjFmfnP7A3j2JxQDdLNhSw\"}}"; + WxCpChatModel modelCard = WxCpChatModel.fromJson(card); + log.info("数据为:" + modelCard.toJson()); + + + /** + * 位置 + */ + String location = "{\"msgid\":\"2641513858500683770_1603876152\",\"action\":\"send\",\"from\":\"icefog\",\"tolist\":[\"wmN6etBgAA0sbJ3invMvRxPQDFoq9uWA\"],\"roomid\":\"\",\"msgtime\":1603876152141,\"msgtype\":\"location\",\"location\":{\"longitude\":116.586285899,\"latitude\":39.911125799,\"address\":\"北京市xxx区xxx路xxx大厦x座\",\"title\":\"xxx管理中心\",\"zoom\":15}}"; + WxCpChatModel modelLocation = WxCpChatModel.fromJson(location); + log.info("数据为:" + modelLocation.toJson()); + + + /** + * 表情 + */ + String emotion = "{\"msgid\":\"6623217619416669654_1603875612\",\"action\":\"send\",\"from\":\"icef\",\"tolist\":[\"wmErxtDgAAhteCglUZH2kUt3rq431qmg\"],\"roomid\":\"\",\"msgtime\":1603875611148,\"msgtype\":\"emotion\",\"emotion\":{\"type\":1,\"width\":290,\"height\":290,\"imagesize\":962604,\"md5sum\":\"94c2b0bba52cc456cb8221b248096612\",\"sdkfileid\":\"4eE1ESTVNalE1TnprMFh6RTJNRE00TnpVMk1UST0aIDc0NzI2NjY1NzE3NTc0Nzg2ZDZlNzg2YTY5NjY2MTYx\"}}"; + WxCpChatModel modelEmotion = WxCpChatModel.fromJson(emotion); + log.info("数据为:" + modelEmotion.toJson()); + + + /** + * 文件 + */ + String file = "{\"msgid\":\"18039699423706571225_1603875608\",\"action\":\"send\",\"from\":\"kens\",\"tolist\":[\"wmErxtDgAArDlFIhf76O6w4GxU81al8w\"],\"roomid\":\"\",\"msgtime\":1603875608214,\"msgtype\":\"file\",\"file\":{\"md5sum\":\"18e93fc2ea884df23b3d2d3b8667b9f0\",\"filename\":\"资料.docx\",\"fileext\":\"docx\",\"filesize\":18181,\"sdkfileid\":\"E4ODRkZjIzYjNkMmQzYjg2NjdiOWYwMDIwMTA1MDIwMTAwMDQwMBI4TkRkZk1UWTRPRGcxTURrek9UZzBPVEF6TTE4eE1EUXpOVGcxTlRVNVh6RTJNRE00TnpVMk1EZz0aIDMwMzkzMzY0NjEzNjM3NjY2NDY1NjMzNjYxMzIzNzYx\"}}"; + WxCpChatModel modelFile = WxCpChatModel.fromJson(file); + log.info("数据为:" + modelFile.toJson()); + + + /** + * 链接 + */ + String link = "{\"msgid\":\"11788441727514772650_1603875624\",\"action\":\"send\",\"from\":\"kenshin\",\"tolist\":[\"0000726\"],\"roomid\":\"\",\"msgtime\":1603875624476,\"msgtype\":\"link\",\"link\":{\"title\":\"邀请你加入群聊\",\"description\":\"技术支持群,进入可查看详情\",\"link_url\":\"https://work.weixin.qq.com/wework_admin/external_room/join/exceed?vcode=xxx\",\"image_url\":\"https://wework.qpic.cn/wwpic/xxx/0\"}}"; + WxCpChatModel modelLink = WxCpChatModel.fromJson(link); + log.info("数据为:" + modelLink.toJson()); + + + /** + * 小程序消息 + */ + String weapp = "{\"msgid\":\"11930598857592605935_1603875608\",\"action\":\"send\",\"from\":\"kens\",\"tolist\":[\"wmGAgeDQAAsgQetTQGqRbMxrkodpM3fA\"],\"roomid\":\"\",\"msgtime\":1603875608691,\"msgtype\":\"weapp\",\"weapp\":{\"title\":\"开始聊天前请仔细阅读服务须知事项\",\"description\":\"客户需同意存档聊天记录\",\"username\":\"xxx@app\",\"displayname\":\"服务须知\"}}"; + WxCpChatModel modelWeapp = WxCpChatModel.fromJson(weapp); + log.info("数据为:" + modelWeapp.toJson()); + + + /** + * 会话记录消息 + */ + String chatrecord = "{\"msgid\":\"11354299838102555191_1603875658\",\"action\":\"send\",\"from\":\"ken\",\"tolist\":[\"icef\"],\"roomid\":\"\",\"msgtime\":1603875657905,\"msgtype\":\"chatrecord\",\"chatrecord\":{\"title\":\"群聊\",\"item\":[{\"type\":\"ChatRecordText\",\"msgtime\":1603875610,\"content\":\"{\\\"content\\\":\\\"test\\\"}\",\"from_chatroom\":false},{\"type\":\"ChatRecordText\",\"msgtime\":1603875620,\"content\":\"{\\\"content\\\":\\\"test2\\\"}\",\"from_chatroom\":false}]}}"; + WxCpChatModel modelChatRecord = WxCpChatModel.fromJson(chatrecord); + log.info("数据为:" + modelChatRecord.toJson()); + + + /** + * 填表消息 + */ + String collect = "{\"msgid\":\"2500536226619379797_1576034482\",\"action\":\"send\",\"from\":\"nick\",\"tolist\":[\"XuJinSheng\",\"15108264797\"],\"roomid\":\"wrjc7bDwYAOAhf9quEwRRxyyoMm0QAAA\",\"msgtime\":1576034482344,\"msgtype\":\"collect\",\"collect\":{\"room_name\":\"这是一个群\",\"creator\":\"nick\",\"create_time\":\"2019-12-11 11:21:22\",\"title\":\"这是填表title\",\"details\":[{\"id\":1,\"ques\":\"表项1,文本\",\"type\":\"Text\"},{\"id\":2,\"ques\":\"表项2,数字\",\"type\":\"Number\"},{\"id\":3,\"ques\":\"表项3,日期\",\"type\":\"Date\"},{\"id\":4,\"ques\":\"表项4,时间\",\"type\":\"Time\"}]}}"; + WxCpChatModel modelCollect = WxCpChatModel.fromJson(collect); + log.info("数据为:" + modelCollect.toJson()); + + + /** + * 红包消息 + */ + String redpacket = "{\"msgid\":\"333590477316965370_1603877439\",\"action\":\"send\",\"from\":\"kens\",\"tolist\":[\"1000000444696\"],\"roomid\":\"\",\"msgtime\":1603877439038,\"msgtype\":\"redpacket\",\"redpacket\":{\"type\":1,\"wish\":\"恭喜发财,大吉大利\",\"totalcnt\":1,\"totalamount\":3000}}"; + WxCpChatModel modelRedpacket = WxCpChatModel.fromJson(redpacket); + log.info("数据为:" + modelRedpacket.toJson()); + + + /** + * 会议邀请信息 + */ + String meeting = "{\"msgid\":\"5935786683775673543_1603877328\",\"action\":\"send\",\"from\":\"ken\",\"tolist\":[\"icef\",\"test\"],\"roomid\":\"wr2vOpDgAAN4zVWKbS\",\"msgtime\":1603877328914,\"msgtype\":\"meeting\",\"meeting\":{\"topic\":\"夕会\",\"starttime\":1603877400,\"endtime\":1603881000,\"address\":\"\",\"remarks\":\"\",\"meetingtype\":102,\"meetingid\":1210342560,\"status\":1}}"; + WxCpChatModel modelMeeting = WxCpChatModel.fromJson(meeting); + log.info("数据为:" + modelMeeting.toJson()); + + + /** + * 切换企业日志 + */ + String switchlog = "{\"msgid\":\"125289002219525886280\",\"action\":\"switch\",\"time\":1554119421840,\"user\":\"XuJinSheng\"}"; + WxCpChatModel modelSwitchLog = WxCpChatModel.fromJson(switchlog); + log.info("数据为:" + modelSwitchLog.toJson()); + + + /** + * 在线文档消息 + */ + String docMsg = "{\"msgid\":\"9732089160923053207_1603877765\",\"action\":\"send\",\"from\":\"ken\",\"tolist\":[\"icef\",\"test\"],\"roomid\":\"wrJawBCQAAStr3jxVxEH\",\"msgtime\":1603877765291,\"msgtype\":\"docmsg\",\"doc\":{\"title\":\"测试&演示客户\",\"doc_creator\":\"test\",\"link_url\":\"https://doc.weixin.qq.com/txdoc/excel?docid=xxx\"}}"; + WxCpChatModel modelDocMsg = WxCpChatModel.fromJson(docMsg); + log.info("数据为:" + modelDocMsg.toJson()); + + + /** + * MarkDown格式消息 + */ + String markDown = "{\"msgid\":\"7546287934688259248_1603875715\",\"action\":\"send\",\"from\":\"ken\",\"tolist\":[\"icef\",\"test\"],\"roomid\":\"wr0SfLCgAAgCaCPeM33UNe\",\"msgtime\":1603875715782,\"msgtype\":\"markdown\",\"info\":{\"content\":\"请前往系统查看,谢谢。\"}}"; + WxCpChatModel modelMarkDown = WxCpChatModel.fromJson(markDown); + log.info("数据为:" + modelMarkDown.toJson()); + + + /** + * 图文消息 + */ + String news = "{\"msgid\":\"118732825779547782215\",\"action\":\"send\",\"from\":\"kens\",\"tolist\":[\"icef\",\"test\"],\"roomid\":\"wrErxtDgAA0jgXE5\",\"msgtime\":1603876045165,\"msgtype\":\"news\",\"info\":{\"item\":[{\"title\":\"service \",\"description\":\"test\",\"url\":\"http://xxx\",\"picurl\":\"https://www.qq.com/xxx.jpg\"}]}}"; + WxCpChatModel modelNews = WxCpChatModel.fromJson(news); + log.info("数据为:" + modelNews.toJson()); + + + /** + * 日程消息 + */ + String calendar = "{\"msgid\":\"2345881211604379705_1603877680\",\"action\":\"send\",\"from\":\"ken\",\"tolist\":[\"icef\",\"test\"],\"roomid\":\"wr2LO0CAAAFrTZCGWWAxBA\",\"msgtime\":1603877680795,\"msgtype\":\"calendar\",\"calendar\":{\"title\":\"xxx业绩复盘会\",\"creatorname\":\"test\",\"attendeename\":[\"aaa\",\"bbb\"],\"starttime\":1603882800,\"endtime\":1603886400,\"place\":\"\",\"remarks\":\"\"}}"; + WxCpChatModel modelCalendar = WxCpChatModel.fromJson(calendar); + log.info("数据为:" + modelCalendar.toJson()); + + + /** + * 混合消息 + */ + String mixed = "{\"msgid\":\"DAQQluDa4QUY0On4kYSABAMgzPrShAE=\",\"action\":\"send\",\"from\":\"HeMiao\",\"tolist\":[\"HeChangTian\",\"LiuZeYu\"],\"roomid\":\"wr_tZ2BwAAUwHpYMwy9cIWqnlU3Hzqfg\",\"msgtime\":1577414359072,\"msgtype\":\"mixed\",\"mixed\":{\"item\":[{\"type\":\"text\",\"content\":\"{\\\"content\\\":\\\"你好[微笑]\\\\n\\\"}\"},{\"type\":\"image\",\"content\":\"{\\\"md5sum\\\":\\\"368b6c18c82e6441bfd89b343e9d2429\\\",\\\"filesize\\\":13177,\\\"sdkfileid\\\":\\\"CtYBMzA2OTAyMDEwMjA0NjIzMDYwMDIwMTAwMDWwNDVmYWY4Y2Q3MDIwMzBmNTliMTAyMDQwYzljNTQ3NzAyMDQ1ZTA1NmFlMjA0MjQ2NjM0NjIzNjY2MzYzNTMyMmQzNzYxMzQ2NDJkMzQ2MjYxNjQyZDM4MzMzMzM4MmQ3MTYyMzczMTM4NjM2NDYxMzczMjY2MzkwMjAxMDAwMjAzMDIwMDEwMDQxMDM2OGI2YzE4YzgyZTY0NDFiZmQ4OWIyNDNlOWQyNDI4MDIwMTAyMDIwMTAwMDQwMBI4TkRkZk2UWTRPRGcxTVRneE5URTFNRGc1TVY4eE1UTTFOak0yTURVeFh6RTFOemMwTVRNek5EYz0aIDQzMTY5NDFlM2MxZDRmZjhhMjEwY2M0NDQzZGUXOTEy\\\"}\"}]}}"; + WxCpChatModel modelMixed = WxCpChatModel.fromJson(mixed); + log.info("获取混合消息,文件对象为:{}", modelMixed.getMixed().getItem().get(0).getContent()); + + // 返回文件对象 + WxCpFileItem wxCpFileItem = WxCpFileItem.fromJson(modelMixed.getMixed().getItem().get(1).getContent()); + log.info("获取混合消息,文件对象为:{}", wxCpFileItem.toJson()); + log.info("数据为:" + modelMixed.toJson()); + + + /** + * 音频存档消息 + */ + String meetingVoiceCall = "{\"msgid\":\"17952229780246929345_1594197637\",\"action\":\"send\",\"from\":\"wo137MCgAAYW6pIiKKrDe5SlzEhSgwbA\",\"tolist\":[\"wo137MCgAAYW6pIiKKrDe5SlzEhSgwbA\"],\"msgtime\":1594197581203,\"msgtype\":\"meeting_voice_call\",\"voiceid\":\"grb8a4c48a3c094a70982c518d55e40557\",\"meeting_voice_call\":{\"endtime\":1594197635,\"sdkfileid\":\"CpsBKjAqd0xhb2JWRUJldGtwcE5DVTB6UjRUalN6c09vTjVyRnF4YVJ5M24rZC9YcHF3cHRPVzRwUUlaMy9iTytFcnc0SlBkZDU1YjRNb0MzbTZtRnViOXV5WjUwZUIwKzhjbU9uRUlxZ3pyK2VXSVhUWVN2ejAyWFJaTldGSkRJVFl0aUhkcVdjbDJ1L2RPbjJsRlBOamJaVDNnPT0SOE5EZGZNVFk0T0RnMU16YzVNVGt5T1RJMk9GOHhNalk0TXpBeE9EZzJYekUxT1RReE9UYzJNemM9GiA3YTYyNzA3NTY4Nzc2MTY3NzQ2MTY0NzA2ZTc4NjQ2OQ==\",\"demofiledata\":[{\"filename\":\"65eb1cdd3e7a3c1740ecd74220b6c627.docx\",\"demooperator\":\"wo137MCgAAYW6pIiKKrDe5SlzEhSgwbA\",\"starttime\":1594197599,\"endtime\":1594197609}],\"sharescreendata\":[{\"share\":\"wo137MCgAAYW6pIiKKrDe5SlzEhSgwbA\",\"starttime\":1594197624,\"endtime\":1594197624}]}}"; + WxCpChatModel modelMeetingVoiceCall = WxCpChatModel.fromJson(meetingVoiceCall); + log.info("数据为:" + modelMeetingVoiceCall.toJson()); + + + /** + * 音频共享文档消息 + */ + String voipDocShare = "{\"msgid\":\"16527954622422422847_1594199256\",\"action\":\"send\",\"from\":\"18002520162\",\"tolist\":[\"wo137MCgAAYW6pIiKKrDe5SlzEhSgwbA\"],\"msgtime\":1594199235014,\"msgtype\":\"voip_doc_share\",\"voipid\":\"gr2751c98b19300571f8afb3b74514bd32\",\"voip_doc_share\":{\"filename\":\"欢迎使用微盘.pdf.pdf\",\"md5sum\":\"ff893900f24e55e216e617a40e5c4648\",\"filesize\":4400654,\"sdkfileid\":\"CpsBKjAqZUlLdWJMd2gvQ1JxMzd0ZjlpdW5mZzJOOE9JZm5kbndvRmRqdnBETjY0QlcvdGtHSFFTYm95dHM2VlllQXhkUUN5KzRmSy9KT3pudnA2aHhYZFlPemc2aVZ6YktzaVh3YkFPZHlqNnl2L2MvcGlqcVRjRTlhZEZsOGlGdHJpQ2RWSVNVUngrVFpuUmo3TGlPQ1BJemlRPT0SOE5EZGZNVFk0T0RnMU16YzVNVGt5T1RJMk9GODFNelUyTlRBd01qQmZNVFU1TkRFNU9USTFOZz09GiA3YTcwNmQ2Zjc5NjY3MDZjNjY2Zjc4NzI3NTZmN2E2YQ==\"}}"; + WxCpChatModel modelVoipDocShare = WxCpChatModel.fromJson(voipDocShare); + log.info("数据为:" + modelVoipDocShare.toJson()); + + + /** + * 互通红包消息 + */ + String externalRedpacket = "{\"msgid\":\"8632214264349267353_1603786184\",\"action\":\"send\",\"from\":\"woJ7ijBwAAmqwojT8r_DaNMbr_NAvaag\",\"tolist\":[\"woJ7ijBwAA6SjS_sIyPLZtyEPJlT7Cfw\",\"tiny-six768\"],\"roomid\":\"wrJ7ijBwAAG1vly_DzVI72Ghc-PtA5Dw\",\"msgtime\":1603786183955,\"msgtype\":\"external_redpacket\",\"redpacket\":{\"type\":1,\"wish\":\"恭喜发财,大吉大利\",\"totalcnt\":2,\"totalamount\":20}}"; + WxCpChatModel modelExternalRedpacket = WxCpChatModel.fromJson(externalRedpacket); + log.info("数据为:" + modelExternalRedpacket.toJson()); + + + /** + * 视频号消息 + */ + String sphfeed = "{\"msgid\":\"5702551662099334532_1619511584_external\",\"action\":\"send\",\"from\":\"yangzhu1\",\"tolist\":[\"wmJSb5CgAA4aWXWndJspQGpJMDbsMwMA\"],\"roomid\":\"\",\"msgtime\":1619511584444,\"msgtype\":\"sphfeed\",\"sphfeed\":{\"feed_type\":4,\"sph_name\":\"云游天地旅行家\",\"feed_desc\":\"瑞士丨盖尔默缆车,名副其实的过山车~\\n\\n#旅行#风景#热门\"}}"; + WxCpChatModel modelSphFeed = WxCpChatModel.fromJson(sphfeed); + log.info("数据为:" + modelSphFeed.toJson()); + + + /** + * 获取会话内容存档开启成员列表 + */ + List permitUserList = cpService.getMsgAuditService().getPermitUserList(null); + log.info(permitUserList.toString()); + + + ArrayList userList = Lists.newArrayList(); + WxCpCheckAgreeRequest checkAgreeRequest = new WxCpCheckAgreeRequest(); + /** + * 获取会话同意情况 + */ + WxCpCheckAgreeRequest.Info info = new WxCpCheckAgreeRequest.Info(); + info.setUserid("wangkai"); + info.setExteranalOpenId("wmOQpTDwAAkOscTrtUlSli0YLU2jcpUg"); + if(info != null){ + userList.add(info); + checkAgreeRequest.setInfo(userList); + } + + WxCpAgreeInfo wxCpAgreeInfo = cpService.getMsgAuditService().checkSingleAgree(checkAgreeRequest); + log.info(wxCpAgreeInfo.toJson()); + + + /** + * 获取会话内容存档内部群信息 + */ + WxCpGroupChat room = cpService.getMsgAuditService().getGroupChat("wrOQpTDwAAyPl84GBJ40W5eWxWtixSCA"); + log.info(room.toJson()); + + } + +}