OpenIMApiClient

This commit is contained in:
wells
2026-08-08 14:56:37 +08:00
parent 0e51812d80
commit aa48225d85
11 changed files with 3931 additions and 232 deletions
@@ -0,0 +1,284 @@
package com.tailbet.common.constant;
/**
* OpenIM 协议相关常量
* <p>
* 统一管理 Webhook 回调命令、请求字段、响应字段、消息类型等协议魔法值,
* 避免散落在 Controller / Service 中。
* </p>
*
* @author socialapp团队
* @since 1.0.7
*/
public final class OpenImConstants {
private OpenImConstants() {
}
// ==================== Webhook 回调命令 ====================
/** 单聊消息发送后回调 */
public static final String CALLBACK_AFTER_SEND_SINGLE_MSG = "callbackAfterSendSingleMsgCommand";
/** 群聊消息发送后回调 */
public static final String CALLBACK_AFTER_SEND_GROUP_MSG = "callbackAfterSendGroupMsgCommand";
/** 成员进群后回调 */
public static final String CALLBACK_AFTER_MEMBER_ENTER_GROUP = "callbackAfterMemberEnterGroupCommand";
/** 成员退群后回调 */
public static final String CALLBACK_AFTER_MEMBER_QUIT_GROUP = "callbackAfterMemberQuitGroupCommand";
/** 用户上线回调 */
public static final String CALLBACK_AFTER_USER_ONLINE = "callbackAfterUserOnlineCommand";
/** 用户下线回调 */
public static final String CALLBACK_AFTER_USER_OFFLINE = "callbackAfterUserOfflineCommand";
// ==================== 请求头 / JSON 字段名 ====================
/** OpenIM Webhook 鉴权请求头名 */
public static final String HEADER_TOKEN = "token";
/** 发送方用户 ID */
public static final String FIELD_SEND_ID = "sendID";
/** 接收方用户 ID */
public static final String FIELD_RECV_ID = "recvID";
/** 群组 IDOpenIM 群 ID */
public static final String FIELD_GROUP_ID = "groupID";
/** 用户 ID */
public static final String FIELD_USER_ID = "userID";
/** 平台 ID */
public static final String FIELD_PLATFORM_ID = "platformID";
/** 消息内容 */
public static final String FIELD_CONTENT = "content";
/** 消息内容类型 */
public static final String FIELD_CONTENT_TYPE = "contentType";
/** 客户端消息 ID */
public static final String FIELD_CLIENT_MSG_ID = "clientMsgID";
/** 服务端消息 ID */
public static final String FIELD_SERVER_MSG_ID = "serverMsgID";
// ==================== Webhook 成功响应 ====================
/** 响应字段:动作码 */
public static final String RESP_ACTION_CODE = "actionCode";
/** 响应字段:错误码 */
public static final String RESP_ERR_CODE = "errCode";
/** 响应字段:错误信息 */
public static final String RESP_ERR_MSG = "errMsg";
/** 响应字段:错误详情 */
public static final String RESP_ERR_DLT = "errDlt";
/** 响应字段:下一动作码 */
public static final String RESP_NEXT_CODE = "nextCode";
/** OpenIM 成功码(actionCode / errCode / nextCode */
public static final int RESP_CODE_SUCCESS = 0;
/** OpenIM 成功响应空字符串字段值 */
public static final String RESP_EMPTY_MSG = "";
// ==================== Token / 鉴权错误码(OpenIM 官方) ====================
/** Token 过期 */
public static final int ERR_TOKEN_EXPIRED = 1501;
/** Token 无效 */
public static final int ERR_TOKEN_INVALID = 1502;
/** Token 格式错误 */
public static final int ERR_TOKEN_MALFORMED = 1503;
/** Token 不存在 */
public static final int ERR_TOKEN_NOT_EXIST = 1504;
/** Token 平台不一致 */
public static final int ERR_TOKEN_DIFFERENT_PLATFORM = 1505;
/** Token 被踢(多端/多实例刷新 adminToken、重复 get_user_token 等) */
public static final int ERR_TOKEN_KICKED = 1506;
/** Token 尚未生效 */
public static final int ERR_TOKEN_NOT_VALID_YET = 1507;
/**
* 服务端代操作使用的平台 ID(Web)。
* 与 App 端 iOS/Android 平台隔离,避免顶掉用户已登录 session。
*/
public static final int PLATFORM_ID_SERVER_WEB = 5;
/** App 端 iOS 平台 ID */
public static final int PLATFORM_ID_IOS = 1;
/** App 端 Android 平台 ID */
public static final int PLATFORM_ID_ANDROID = 2;
// ==================== 会话摘要 / 未读 ====================
/** 会话 lastMessage 摘要最大长度 */
public static final int CONVERSATION_CONTENT_MAX_LEN = 100;
/** 未读数自增 SQL 片段 */
public static final String SQL_UNREAD_COUNT_INCREMENT = "unread_count = unread_count + 1";
/** 新建会话初始未读数(接收方) */
public static final int UNREAD_COUNT_INITIAL_RECEIVER = 1;
/** 新建会话初始未读数(发送方) */
public static final int UNREAD_COUNT_INITIAL_SENDER = 0;
// ==================== OpenIM contentType ====================
/** 文本 */
public static final int CONTENT_TYPE_TEXT = 101;
/** 图片 */
public static final int CONTENT_TYPE_IMAGE = 102;
/** 语音 */
public static final int CONTENT_TYPE_VOICE = 103;
/** 视频 */
public static final int CONTENT_TYPE_VIDEO = 104;
/** 文件 */
public static final int CONTENT_TYPE_FILE = 105;
/** 位置 */
public static final int CONTENT_TYPE_LOCATION = 106;
/** 名片 */
public static final int CONTENT_TYPE_CARD = 114;
/** 自定义消息 */
public static final int CONTENT_TYPE_CUSTOM = 110;
// ==================== OpenIM sessionType ====================
/** 单聊 */
public static final int SESSION_TYPE_SINGLE = 1;
/** 群聊 */
public static final int SESSION_TYPE_GROUP = 3;
// ==================== 离线推送 extras / 文案 ====================
/** 推送业务类型:IM 离线消息 */
public static final String PUSH_BIZ_TYPE_IM_MESSAGE = "IM_MESSAGE";
/** 推送标题 */
public static final String PUSH_TITLE_NEW_MESSAGE = "您有新消息";
/** 发送方昵称兜底 */
public static final String PUSH_DEFAULT_SENDER_NAME = "用户";
/** 系统/管理员代发时的发送方昵称兜底(如 OpenIM imAdmin */
public static final String PUSH_DEFAULT_SYSTEM_SENDER_NAME = "系统";
/** 群名称兜底 */
public static final String PUSH_DEFAULT_GROUP_NAME = "群聊";
/** extras:会话 ID */
public static final String EXTRAS_CONVERSATION_ID = "conversationId";
/** extras:发送方 ID */
public static final String EXTRAS_SENDER_ID = "senderId";
/** extras:消息类型 */
public static final String EXTRAS_MESSAGE_TYPE = "messageType";
/** extras:会话类型 */
public static final String EXTRAS_SESSION_TYPE = "sessionType";
/** extras:本地群组 ID */
public static final String EXTRAS_GROUP_ID = "groupId";
/** 单聊 conversationId 前缀 */
public static final String CONVERSATION_ID_SINGLE_PREFIX = "si_";
/** 群聊 conversationId 前缀(业务推送 extras 约定,非 OpenIM 原生 ID */
public static final String CONVERSATION_ID_GROUP_PREFIX = "group:";
/**
* OpenIM 原生群聊 conversationID 前缀(sessionType=3 ReadGroupChat
* 形如 {@code sg_{openimGroupId}}
*/
public static final String OPENIM_NATIVE_GROUP_CONVERSATION_PREFIX = "sg_";
/** 单聊 conversationId 分隔符 */
public static final String CONVERSATION_ID_SEPARATOR = "_";
/** 推送正文最大长度(对齐 PushSendReq */
public static final int PUSH_CONTENT_MAX_LEN = 200;
/** 推送 bizId 最大长度(对齐 PushSendReq */
public static final int PUSH_BIZ_ID_MAX_LEN = 64;
/** 推送摘要最大长度 */
public static final int PUSH_SUMMARY_MAX_LEN = 50;
/** 单次 Feign 推送批量用户数 */
public static final int PUSH_BATCH_SIZE = 500;
/** 离线推送幂等 TTL(分钟) */
public static final long PUSH_DEDUP_TTL_MINUTES = 10L;
/** Redis 幂等占位值 */
public static final String PUSH_DEDUP_PLACEHOLDER = "1";
/** 推送正文:昵称与摘要分隔符 */
public static final String PUSH_BODY_NAME_CONTENT_SEPARATOR = "";
/** 推送正文:群名与发送者分隔符 */
public static final String PUSH_BODY_GROUP_SEPARATOR = " | ";
/** 摘要:图片 */
public static final String SUMMARY_IMAGE = "[图片]";
/** 摘要:语音 */
public static final String SUMMARY_VOICE = "[语音]";
/** 摘要:视频 */
public static final String SUMMARY_VIDEO = "[视频]";
/** 摘要:文件 */
public static final String SUMMARY_FILE = "[文件]";
/** 摘要:位置 */
public static final String SUMMARY_LOCATION = "[位置]";
/** 摘要:名片 */
public static final String SUMMARY_CARD = "[名片]";
/** 摘要:其他消息 */
public static final String SUMMARY_DEFAULT = "[消息]";
/** JSON 对象起始字符(用于判断 content 是否为 JSON 字符串) */
public static final char JSON_OBJECT_START = '{';
/** 自定义消息 content.data / extension 字段 */
public static final String FIELD_DATA = "data";
/** 自定义消息 extension 字段 */
public static final String FIELD_EXTENSION = "extension";
/** 业务自定义类型字段 */
public static final String FIELD_CUSTOM_TYPE = "customType";
/**
* 红包领取提醒:仅聊天内系统记录,禁止离线推送 / 系统通知
*/
public static final String CUSTOM_TYPE_RED_ENVELOPE_CLAIM_NOTICE = "red_envelope_claim_notice";
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,113 @@
package com.tailbet.common.exception;
import com.tailbet.common.enums.ErrorCodeEnum;
import lombok.Getter;
/**
* 业务异常
* <p>
* 封装业务逻辑层面的异常,区别于系统运行时异常。
* 业务异常通常有明确的错误码和提示信息,可直接返回给前端展示。
* 使用时优先使用预定义的错误码枚举,也支持自定义消息。
* </p>
*
* @author socialapp团队
* @since 1.0.0
*/
@Getter
public class BusinessException extends RuntimeException {
/**
* 错误码
*/
private final int code;
/**
* 附加数据(如当前场次信息等)
*/
private final Object data;
/**
* 基于错误码枚举构造业务异常
*
* @param errorCode 错误码枚举
*/
public BusinessException(ErrorCodeEnum errorCode) {
super(errorCode.getMessage());
this.code = errorCode.getCode();
this.data = null;
}
/**
* 基于错误码枚举和自定义消息构造业务异常
*
* @param errorCode 错误码枚举
* @param message 自定义错误消息
*/
public BusinessException(ErrorCodeEnum errorCode, String message) {
super(message);
this.code = errorCode.getCode();
this.data = null;
}
/**
* 基于错误码枚举、自定义消息和原因构造业务异常
*
* @param errorCode 错误码枚举
* @param message 自定义错误消息
* @param cause 原始异常
*/
public BusinessException(ErrorCodeEnum errorCode, String message, Throwable cause) {
super(message, cause);
this.code = errorCode.getCode();
this.data = null;
}
/**
* 基于状态码和自定义消息构造业务异常
*
* @param code 状态码
* @param message 错误消息
*/
public BusinessException(int code, String message) {
super(message);
this.code = code;
this.data = null;
}
/**
* 基于自定义消息构造业务异常(默认错误码 INTERNAL_ERROR
*
* @param message 错误消息
*/
public BusinessException(String message) {
super(message);
this.code = ErrorCodeEnum.INTERNAL_ERROR.getCode();
this.data = null;
}
/**
* 基于错误码枚举和附加数据构造业务异常
* <p>
* 用于需要向前端返回额外数据的异常场景,
* 如 LIVE_ALREADY_ACTIVE 时携带已有场次信息。
* </p>
*
* @param errorCode 错误码枚举
* @param data 附加数据
*/
public BusinessException(ErrorCodeEnum errorCode, Object data) {
super(errorCode.getMessage());
this.code = errorCode.getCode();
this.data = data;
}
/**
* 获取对应的错误码枚举
*
* @return 错误码枚举
*/
public ErrorCodeEnum getErrorCodeEnum() {
return ErrorCodeEnum.of(this.code);
}
}