mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2025-06-28 13:16:19 +08:00
🆕 #1596 【企业微信】新增会话存档相关接口
This commit is contained in:
parent
b8dd04b89f
commit
c0535f87fb
@ -38,6 +38,10 @@ public class WxCpProperties {
|
||||
* 微信企业号应用 EncodingAESKey
|
||||
*/
|
||||
private String aesKey;
|
||||
/**
|
||||
* 微信企业号应用 会话存档类库路径
|
||||
*/
|
||||
private String msgAuditLibPath;
|
||||
|
||||
/**
|
||||
* 配置存储策略,默认内存
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 对公众平台发送给公众账号的消息加解密示例代码.
|
||||
|
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");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
* 配置:
|
||||
* <xml>
|
||||
* <corpId>wwa3bexxXXXXXX</corpId>
|
||||
* <agentId>自定义agentId</agentId>
|
||||
* <corpSecret>xIpum7Yt4NMXXXXXXX</corpSecret>
|
||||
* <token>2bSNqXXXXXXXX</token>
|
||||
* <aesKey>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</aesKey>
|
||||
*
|
||||
* 注意:最好先配置lib开头的系统库,再配置sdk类库,配置绝对路径,最好配置为linux路径
|
||||
* windows:
|
||||
* <msgAuditLibPath>D:/WorkSpace/libcrypto-1_1-x64.dll,libssl-1_1-x64.dll,libcurl-x64.dll,WeWorkFinanceSdk.dll,libWeWorkFinanceSdk_Java.so</msgAuditLibPath>
|
||||
* linux:
|
||||
* <msgAuditLibPath>/www/osfile/work_msg_storage/libcrypto-1_1-x64.dll,libssl-1_1-x64.dll,libcurl-x64.dll,WeWorkFinanceSdk.dll,libWeWorkFinanceSdk_Java.so</msgAuditLibPath>
|
||||
* </xml>
|
||||
*/
|
||||
|
||||
/**
|
||||
* 建议放到redis,本次请求获取消息记录开始的seq值。首次访问填写0,非首次使用上次企业微信返回的最大seq。允许从任意seq重入拉取。
|
||||
*/
|
||||
long seq = 0L;
|
||||
|
||||
/**
|
||||
* 图片,语音,视频,表情,文件,音频存档消息,音频共享文档消息调用 获取媒体消息
|
||||
*/
|
||||
List<String> 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<WxCpChatDatas.WxCpChatData> chatdata = chatDatas.getChatData();
|
||||
Iterator<WxCpChatDatas.WxCpChatData> 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<String> permitUserList = cpService.getMsgAuditService().getPermitUserList(null);
|
||||
log.info(permitUserList.toString());
|
||||
|
||||
|
||||
ArrayList<WxCpCheckAgreeRequest.Info> 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());
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user