【内容】表情、敏感词
本篇讲两块内容能力:聊天用的表情,以及发消息时的敏感词过滤。分别由 yudao-module-im 后端模块的 face、sensitiveword 包实现。
- 表情:运营配置的系统表情包,加上用户自己收藏的个人表情,涉及
im_face_pack、im_face_pack_item、im_face_user_item三张表。 - 敏感词:运营维护一份敏感词库(
im_sensitive_word),发消息时自动校验拦截。
# 1. 表情
表情分两类:系统表情包(运营配置,全员可用)和个人表情(用户自己收藏,仅自己可用)。聊天里发出的表情是消息类型「表情」(见 《消息》);Unicode emoji 仍走文本,不在此列。
# 1.1 表结构
省略 creator/create_time/updater/update_time/deleted/tenant_id 等通用字段
表情拆成两组表:内置表情包(运营配置、全员可用)与自定义表情(用户自己收藏)。
# 内置表情包
「表情包 + 表情项」主子结构:
CREATE TABLE `im_face_pack` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
`name` varchar(64) NOT NULL COMMENT '表情包名称',
`icon` varchar(512) DEFAULT NULL COMMENT '表情包图标(面板底部 tab 显示)',
`sort` int NOT NULL DEFAULT '0' COMMENT '排序',
`status` tinyint NOT NULL DEFAULT '0' COMMENT '状态;参见 CommonStatusEnum',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='IM 表情包表';
CREATE TABLE `im_face_pack_item` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
`pack_id` bigint NOT NULL COMMENT '所属表情包编号',
`url` varchar(512) NOT NULL COMMENT '表情图 URL',
`name` varchar(64) DEFAULT NULL COMMENT '表情名(可选,如「狗头」「捂脸」)',
`width` int NOT NULL DEFAULT '0' COMMENT '渲染宽度(像素)',
`height` int NOT NULL DEFAULT '0' COMMENT '渲染高度(像素)',
`sort` int NOT NULL DEFAULT '0' COMMENT '排序',
`status` tinyint NOT NULL DEFAULT '0' COMMENT '状态;参见 CommonStatusEnum',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='IM 表情包项表';
① im_face_pack 是表情包:name 包名、icon 是表情面板底部切换 tab 的图标。
② im_face_pack_item 是包里的每个表情:pack_id 关联表情包,url 表情图,width / height 是渲染尺寸。im_face_pack 与 im_face_pack_item 都有 status(启用 / 停用),只有启用的才下发到客户端。
# 自定义表情
用户自己收藏的个人表情,结构与表情项类似,但属主是用户:
CREATE TABLE `im_face_user_item` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
`user_id` bigint NOT NULL COMMENT '所属用户编号',
`url` varchar(512) NOT NULL COMMENT '表情图 URL',
`name` varchar(64) DEFAULT NULL COMMENT '表情名(可选)',
`width` int NOT NULL DEFAULT '0' COMMENT '渲染宽度(像素)',
`height` int NOT NULL DEFAULT '0' COMMENT '渲染高度(像素)',
`sort` int NOT NULL DEFAULT '0' COMMENT '排序',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='IM 用户个人表情表';
① user_id 表情归属的用户,每个用户只看到自己的个人表情;其余 url / name / width / height 字段与表情项一致。
# 1.2 用户侧
输入框的表情按钮打开表情面板(FacePicker.vue),底部 tab 切换「个人表情 + 各系统表情包」:
- 系统表情包由 ImFacePackController 的
getFacePackList方法一次性返回(启用的包 + 包内启用的表情)。 - 个人表情由 ImFaceUserItemController 提供:
getFaceUserItemList拉自己的收藏,createFaceUserItem添加、deleteFaceUserItem删除。在聊天里右键一张图片 / 表情消息选「添加到表情」,即收藏为个人表情。

# 1.3 运营后台
对应 [IM 即时通讯 -> 表情管理] 菜单,对应 @/views/im/manager/face 目录:
- 系统表情:维护表情包及包内表情项,由 ImFacePackManagerController、ImFacePackItemManagerController 提供新增 / 修改 / 删除。
- 用户表情:由 ImFaceUserItemManagerController 查询用户上传的个人表情,便于运营排查。

点某个表情包行的「管理表情」,进入维护包内表情项(增 / 删 / 改):


# 2. 敏感词
敏感词是一份词库,发文本消息时自动校验:命中则拦截发送。它只在运营后台维护,用户侧无独立菜单,发消息时由后端自动校验。
# 2.1 表结构
省略 creator/create_time/updater/update_time/deleted/tenant_id 等通用字段
CREATE TABLE `im_sensitive_word` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
`word` varchar(255) NOT NULL COMMENT '敏感词',
`status` tinyint NOT NULL DEFAULT '0' COMMENT '状态(0=开启,1=禁用)',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_im_sensitive_word_word` (`word`)
) ENGINE=InnoDB COMMENT='IM 敏感词表';
① word 敏感词,全局唯一;status 控制该词是否生效(禁用的词不参与校验)。
# 2.2 运营后台
对应 [IM 即时通讯 -> 敏感词管理] 菜单,对应 @/views/im/manager/sensitiveword 目录,由 ImSensitiveWordManagerController 提供新增 / 修改 / 删除 / 批量删除 / 分页查询。

# 2.3 发送前校验
发文本消息时,ImPrivateMessageServiceImpl / ImGroupMessageServiceImpl 在落库前调用 ImSensitiveWordService 的 validateText 方法校验内容;命中敏感词则抛异常、阻止发送。校验逻辑属于消息发送主流程的一环,详见 《消息》。
匹配用开源库 houbb/sensitive-word (opens new window)(SensitiveWordBs)实现:它把词库构建成 DFA / 前缀树,对文本一次扫描即可判断是否命中,性能好、不必逐词遍历。服务端按租户各缓存一份 SensitiveWordBs 实例(每租户一套词库),敏感词增删改后本机立即失效重建、多实例靠定时任务刷新,最长 1 分钟内收敛。