mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2026-03-10 00:13:40 +08:00
🆕 #1596 【企业微信】新增会话存档相关接口
This commit is contained in:
207
weixin-java-cp/src/main/java/com/tencent/wework/Finance.java
Normal file
207
weixin-java-cp/src/main/java/com/tencent/wework/Finance.java
Normal file
@@ -0,0 +1,207 @@
|
||||
package com.tencent.wework;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 注意:
|
||||
* 此类必须配置在com.tencent.wework路径底下,否则会报错:
|
||||
* java.lang.UnsatisfiedLinkError: com.xxx.Finance.NewSdk()
|
||||
* <p>
|
||||
* Q:JAVA版本的sdk报错UnsatisfiedLinkError?
|
||||
* A:请检查是否修改了sdk的包名。
|
||||
* <p>
|
||||
* 官方文档:
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
* <p>
|
||||
* 如需自行实现,亦可调用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;
|
||||
|
||||
/**
|
||||
* 获取会话内容存档开启成员列表
|
||||
* 企业可通过此接口,获取企业开启会话内容存档的成员列表
|
||||
* <p>
|
||||
* 请求方式: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<String> getPermitUserList(Integer type) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 获取会话内容存档内部群信息
|
||||
* 企业可通过此接口,获取会话内容存档本企业的内部群信息,包括群名称、群主id、公告、群创建时间以及所有群成员的id与加入时间。
|
||||
* <p>
|
||||
* 请求方式: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;
|
||||
|
||||
/**
|
||||
* 获取会话同意情况
|
||||
* 企业可通过下述接口,获取会话中外部成员的同意情况
|
||||
* <p>
|
||||
* 单聊请求地址:https://qyapi.weixin.qq.com/cgi-bin/msgaudit/check_single_agree?access_token=ACCESS_TOKEN
|
||||
* <p>
|
||||
* 请求方式:POST(HTTPS)
|
||||
*
|
||||
* @param checkAgreeRequest 待查询的会话信息
|
||||
* @return
|
||||
* @throws WxErrorException
|
||||
*/
|
||||
WxCpAgreeInfo checkSingleAgree(@NonNull WxCpCheckAgreeRequest checkAgreeRequest) throws WxErrorException;
|
||||
|
||||
}
|
||||
@@ -399,6 +399,13 @@ public interface WxCpService extends WxService {
|
||||
*/
|
||||
WxCpLivingService getLivingService();
|
||||
|
||||
/**
|
||||
* 获取会话存档相关接口的服务类对象
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
WxCpMsgAuditService getMsgAuditService();
|
||||
|
||||
/**
|
||||
* 获取日历相关接口的服务类对象
|
||||
*
|
||||
|
||||
@@ -50,6 +50,7 @@ public abstract class BaseWxCpServiceImpl<H, P> 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);
|
||||
@@ -484,6 +485,11 @@ public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestH
|
||||
return livingService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxCpMsgAuditService getMsgAuditService() {
|
||||
return msgAuditService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxCpOaCalendarService getOaCalendarService() {
|
||||
return this.oaCalendarService;
|
||||
|
||||
@@ -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<String> 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<List<String>>() {
|
||||
}.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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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> 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<WxCpChatData> 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<ChatRecordItem> 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> 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 List<NewsItem> newsItem;
|
||||
|
||||
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> 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> demoFileData;
|
||||
|
||||
@SerializedName("sharescreendata")
|
||||
private List<ShareScreenData> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<Member> 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -174,6 +174,13 @@ public interface WxCpConfigStorage {
|
||||
*/
|
||||
String getAesKey();
|
||||
|
||||
/**
|
||||
* 获取企微会话存档系统库 绝对路径
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getMsgAuditLibPath();
|
||||
|
||||
/**
|
||||
* Gets expires time.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user