企业解决方案二十一-企微消息接收后提炼关键信息并转发方案实现

一、项目背景与需求分析

1.1 业务场景

在企业日常运营中,客服人员需要同时处理来自多个企业微信群和个人好友的咨询消息。传统的人工处理方式存在以下痛点:

  • 消息分散:消息分散在不同群组和好友对话中,难以集中管理

  • 响应滞后:人工逐一回复效率低下,客户等待时间长

  • 信息孤岛:重要信息无法自动流转到相关部门

  • 重复劳动:相似问题需要反复回答

1.2 系统目标

本文设计并实现了一套企业微信消息接收与转发系统,核心功能包括:

  1. 实时消息监听:通过Python脚本监听企业微信消息,推送到Java后端

  2. 智能消息聚合:将短时间内的多条消息智能合并,减少大模型调用次数

  3. AI智能回复:接入扣子(Coze)大模型,实现自动问答

  4. 灵活转发配置:支持将指定来源的消息转发到指定目标群组

  5. 结构化信息提取:从消息中提取车牌号、姓名、手机号等关键信息

二、系统架构设计

2.1 整体架构

text

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                         前端Vue管理界面                          │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
│  │好友/群管理│ │关系绑定配置│ │消息记录  │ │  登录/注册       │ │
│  └──────────┘ └──────────┘ └──────────┘ └──────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
                              │ HTTP
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                    Spring Boot 后端服务                         │
│  ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐  │
│  │  BigController│ │  定时任务     │ │  消息处理引擎        │  │
│  │  (核心控制器) │ │  (定时刷新)   │ │  (聚合/过滤/转发)    │  │
│  └──────────────┘ └──────────────┘ └──────────────────────┘  │
│  ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐  │
│  │  Coze大模型   │ │  OSS存储     │ │  邮件服务            │  │
│  │  智能体调用   │ │  图片上传    │ │  验证码              │  │
│  └──────────────┘ └──────────────┘ └──────────────────────┘  │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                        数据存储层                               │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌────────────────────┐ │
│  │ MySQL   │ │ 本地文件 │ │  Redis  │ │  阿里云OSS         │ │
│  │ (主数据) │ │(消息缓存)│ │ (可选)  │ │  (图片存储)        │ │
│  └─────────┘ └─────────┘ └─────────┘ └────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                      企业微信客户端                             │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐   │
│  │ 群聊消息  │ │ 私聊消息  │ │ 图片消息  │ │  位置消息    │   │
│  └──────────┘ └──────────┘ └──────────┘ └──────────────┘   │
└─────────────────────────────────────────────────────────────────┘

2.2 技术选型

技术组件 选型 说明
后端框架 Spring Boot 2.x 企业级微服务框架
ORM框架 MyBatis-Plus 简化数据库操作
前端框架 Vue 2.x + Element UI 后台管理界面
消息监听 Python + 企业微信SDK 实时监听消息
AI引擎 扣子(Coze)大模型 智能回复与信息提取
数据库 MySQL 8.0 主数据存储
文件存储 阿里云OSS 图片存储
JSON处理 Fastjson + Gson + Jackson 多格式解析

三、核心功能实现

3.1 消息监听与接收

3.1.1 Python消息监听端

系统通过Python脚本实时监听企业微信消息,主要监听的消息类型包括:

类型码 消息类型 说明
11041 文本消息 用户发送的文本内容
11042 图片消息 用户发送的图片
11046 位置消息 用户共享的位置信息
11078 群名称变更 群聊名称修改通知

Python端将监听到的消息封装后,通过HTTP请求发送到Java后端的/big/receive_python_msg接口。

3.1.2 消息数据模型

java

复制代码
// 微信消息信息封装
public class WxInfo {
    private String id;           // 消息唯一ID
    private String sender;       // 发送者信息 (名称&&&ID)
    private String groupName;    // 群聊信息 (名称&&&ID)
    private String sendContent;  // 发送内容
    private String imageUrl;     // 图片URL
    private String mapInfo;      // 位置信息
    private long sendTime;       // 发送时间戳
}

// Python推送消息解析类
static class ChatInfoJson {
    ChatData data;
}

static class ChatData {
    String sender;           // 发送者userId
    String conversation_id;  // 对话ID
    String sender_name;      // 发送者名称
    String content;          // 消息内容
    String send_time;        // 发送时间
    String receiver;         // 接收者
    String title;            // 位置标题
    String address;          // 位置地址
    Cdn cdn;                 // CDN信息(图片)
    double latitude;         // 纬度
    double longitude;        // 经度
}

3.2 消息处理流程

3.2.1 消息处理流程图

text

复制代码
┌─────────────────────────────────────────────────────────────┐
│                     接收到消息                              │
└───────────────────────┬─────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────┐
│              判断消息类型 (11041/11042/11046)              │
└───────────────────────┬─────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────┐
│             判断是否自己发送 (sender == SELF_ID)           │
│             是 → 忽略 (不记录自己发送的消息)                │
│             否 → 继续处理                                   │
└───────────────────────┬─────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────┐
│               构建 WxInfo 对象并存储                        │
│   ┌─────────────────────────────────────────────────┐      │
│   │  文本消息 → 直接保存内容                        │      │
│   │  图片消息 → 下载图片到本地                      │      │
│   │  位置消息 → 解析经纬度/标题/地址               │      │
│   └─────────────────────────────────────────────────┘      │
└───────────────────────┬─────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────┐
│             添加到内存列表 Constants.WX_INFO_LIST          │
│             写入本地文件 wx_info_list.txt                  │
└───────────────────────┬─────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────┐
│             判断消息数量 > 10 或 超时 5分钟                │
└───────────────────────┬─────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────┐
│                   消息聚合处理                              │
│   ┌─────────────────────────────────────────────────┐      │
│   │  按发送者/群组 聚合多条消息                      │      │
│   │  合并内容、图片、位置等信息                      │      │
│   └─────────────────────────────────────────────────┘      │
└───────────────────────┬─────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────┐
│                 判断是否包含手机号或图片                    │
│              是 → 调用大模型提取信息                       │
│              否 → 仅保存,不转发                          │
└───────────────────────┬─────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────┐
│             查询转发配置 (relation_detail)                  │
│             根据来源ID查询目标ID列表                        │
└───────────────────────┬─────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────┐
│             执行消息转发                                    │
│   ┌─────────────────────────────────────────────────┐      │
│   │  发送文本消息 (包含车牌/姓名/手机号)            │      │
│   │  发送位置消息 (如有)                            │      │
│   │  发送图片消息 (如有)                            │      │
│   └─────────────────────────────────────────────────┘      │
└─────────────────────────────────────────────────────────────┘
3.2.2 消息聚合策略

为了避免频繁调用大模型API造成资源浪费,系统实现了智能消息聚合机制:

java

复制代码
// 消息聚合核心逻辑 (Step5_InfoIntegrator.integrateWxInfosWithRelation)
public static List<MergeRelation> integrateWxInfosWithRelation(List<WxInfo> wxInfoList) {
    // 1. 按发送者/群组分组
    Map<String, List<WxInfo>> groupMap = wxInfoList.stream()
        .collect(Collectors.groupingBy(wxInfo -> {
            if (wxInfo.getGroupName().contains("R:")) {
                return wxInfo.getGroupName(); // 群组维度
            } else {
                return wxInfo.getSender(); // 个人维度
            }
        }));
    
    // 2. 对每组消息进行合并
    List<MergeRelation> mergeRelations = new ArrayList<>();
    for (Map.Entry<String, List<WxInfo>> entry : groupMap.entrySet()) {
        MergeRelation relation = new MergeRelation();
        relation.setOriginalInfos(entry.getValue());
        relation.setMergedInfo(mergeWxInfo(entry.getValue()));
        mergeRelations.add(relation);
    }
    return mergeRelations;
}

3.3 图片处理

3.3.1 图片下载与存储

当接收到图片消息时,系统需要从企业微信CDN下载图片:

java

复制代码
case 11042:
    // 图片消息处理
    String savePath = Constants.IMAGE_SAVE_PATH + "\\" + System.currentTimeMillis() + ".jpg";
    Map<String, Object> result1 = downloadImage(
        1, 1, 
        chatInfoJson.data.cdn.url, 
        chatInfoJson.data.cdn.auth_key, 
        chatInfoJson.data.cdn.aes_key, 
        chatInfoJson.data.cdn.size, 
        savePath
    );
    imageUrl = savePath;
    tempSendContent = "发送的图片消息---";
    mark = "image";
    break;
3.3.2 图片转发

转发图片时,需要将本地路径中的反斜杠转换为双反斜杠:

java

复制代码
if ((coze9Res.imageUrl != null) && !coze9Res.imageUrl.equals("null")) {
    String imagePath = coze9Res.imageUrl.replaceAll("&&", "\\\\\\\\");
    Step5_SendImage.doWorkSend(tempRelationDetail.getOneTar(), imagePath);
}

3.4 大模型智能处理

3.4.1 信息提取智能体

系统调用扣子大模型进行结构化信息提取:

java

复制代码
String uploadInfo = Step9_InfoExtractSmart.SmartWork(
    UUID.randomUUID().toString(), 
    wxInfo.toString()
);

// 解析返回结果
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
Coze9Res coze9Res = mapper.readValue(uploadInfo, Coze9Res.class);

Coze9Res 数据结构:

java

复制代码
public class Coze9Res {
    private String licensePlateNumber;  // 车牌号
    private String name;                // 姓名
    private String phone;               // 手机号
    private String sendContent;         // 原始发送内容
    private String imageUrl;            // 图片URL
    private String mapInfo;             // 位置信息
}
3.4.2 智能回复

系统还支持大模型自动回复:

java

复制代码
public void modelGiveAnswer(String user_id, Boolean group, String addId) throws Exception {
    QueryWrapper<Msg> msgQueryWrapper = new QueryWrapper<>();
    String finalQueryId = group ? user_id + addId : user_id;
    msgQueryWrapper.eq("chat_room_or_user_id", finalQueryId);
    List<Msg> msgList = msgMapper.selectList(msgQueryWrapper);
    
    String answer = Step2_AnswerSmart.SmartWork(
        "7642293093576425524",  // botId
        finalQueryId,           // user_id
        msgList                 // 历史消息列表
    );
    // 保存回复内容到数据库
}

3.5 转发关系配置

3.5.1 数据模型

java

复制代码
// 关系主表
public class Relation {
    private Integer id;
    private String src;   // 来源ID列表,用---分隔
    private String tar;   // 目标ID列表,用---分隔
}

// 关系明细表
public class RelationDetail {
    private Integer id;
    private Integer relationId;  // 关联主表ID
    private String oneSrc;       // 单个来源ID
    private String oneTar;       // 单个目标ID
}
3.5.2 配置管理界面

前端Vue界面实现了可视化的关系绑定配置:

vue

复制代码
<div class="selection-area">
  <!-- 左侧:接收消息的来源 -->
  <div class="selection-panel left-panel">
    <div class="panel-header">
      <span><strong>接收消息来源</strong></span>
    </div>
    <div class="panel-body">
      <el-checkbox-group v-model="selectedSources">
        <div v-for="item in filteredSourceList" :key="item.id">
          <el-checkbox :label="item.id">
            {{ item.type === 'group' ? '👥' : '👤' }} {{ item.name }}
          </el-checkbox>
        </div>
      </el-checkbox-group>
    </div>
  </div>

  <!-- 右侧:转发到的目标 -->
  <div class="selection-panel right-panel">
    <div class="panel-header">
      <span><strong>转发到目标</strong></span>
    </div>
    <div class="panel-body">
      <el-checkbox-group v-model="selectedTargets">
        <div v-for="item in filteredTargetList" :key="item.id">
          <el-checkbox :label="item.id">
            {{ item.type === 'group' ? '👥' : '👤' }} {{ item.name }}
          </el-checkbox>
        </div>
      </el-checkbox-group>
    </div>
  </div>
</div>

3.6 定时任务

系统配置了两个定时任务进行数据同步:

java

复制代码
// 每10分钟刷新好友和群信息
@Scheduled(fixedRate = 10 * 60 * 1000)
public void scheduledRefresh() {
    Step1_Friend.doWork();   // 同步好友列表
    Step2_Friend.doWork();   // 同步好友详细信息
}

// 每12小时全量刷新群信息
@Scheduled(fixedRate = 30 * 720 * 60 * 1000)
public void scheduledRefreshGroup() {
    Step3_GroupOnce.doWork(); // 全量同步群列表
}

3.7 文件持久化

3.7.1 消息缓存文件

系统使用本地文件 wx_info_list.txt 作为消息缓存,防止内存溢出:

java

复制代码
public static void appendToFile(WxInfo wxInfo) {
    lock.writeLock().lock();
    try {
        List<WxInfo> existingList = loadFromFile();
        existingList.add(wxInfo);
        writeFullArray(existingList);
    } finally {
        lock.writeLock().unlock();
    }
}

private static void writeFullArray(List<WxInfo> list) throws IOException {
    ObjectMapper prettyMapper = new ObjectMapper();
    prettyMapper.enable(SerializationFeature.INDENT_OUTPUT);
    prettyMapper.writeValue(new File(FILE_PATH), list);
}
3.7.2 读写锁保护

使用 ReentrantReadWriteLock 保证多线程安全:

java

复制代码
private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

// 读操作使用读锁
public static List<WxInfo> loadFromFile() {
    lock.readLock().lock();
    try {
        // 读取文件
    } finally {
        lock.readLock().unlock();
    }
}

// 写操作使用写锁
public static void appendToFile(WxInfo wxInfo) {
    lock.writeLock().lock();
    try {
        // 写入文件
    } finally {
        lock.writeLock().unlock();
    }
}

四、前端管理界面

4.1 好友与群管理

vue

复制代码
<template>
  <div>
    <!-- 好友列表 -->
    <el-table :data="friendList" border>
      <el-table-column prop="nickName" label="昵称"></el-table-column>
      <el-table-column prop="userId" label="用户ID"></el-table-column>
      <el-table-column prop="remark" label="备注"></el-table-column>
      <el-table-column prop="conversationId" label="会话ID"></el-table-column>
    </el-table>

    <!-- 群列表 -->
    <el-table :data="groupList" border>
      <el-table-column prop="nickName" label="群名称"></el-table-column>
      <el-table-column prop="chatRoomId" label="群ID"></el-table-column>
    </el-table>
  </div>
</template>

4.2 关系绑定配置界面

界面采用左右双栏设计:

  • 左侧面板:显示所有可选的来源(好友和群聊),支持搜索过滤

  • 右侧面板:显示所有可选的目标(好友和群聊),支持搜索过滤

  • 预览区域:实时展示当前选择的来源→目标映射关系

  • 关系列表:展示所有已保存的绑定关系,支持编辑和删除

4.3 登录与注册

4.3.1 邮箱验证码

java

复制代码
@PostMapping("/email_code")
public Res email_code(@RequestBody User user) {
    // 5分钟内验证码有效
    long diffLongTime = nowTime.getTime() - existEmail.getSendTime().getTime();
    if (diffLongTime <= (5 * 60 * 1000)) {
        return Res.error(Constants.CODE_600, "验证码5分钟内有效,请5分钟后再获取");
    }
    // 生成4位随机验证码并发送邮件
    String code = RandomUtil.randomNumbers(4);
    javaMailSender.send(simpleMailMessage);
}
4.3.2 密码加密存储

java

复制代码
// 使用SHA256加密
user.setPassword(MyUtils.getSHA256StrJava(user.getPassword()));

// SHA256工具方法
public static String getSHA256StrJava(String str) {
    MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
    byte[] hash = messageDigest.digest(str.getBytes(StandardCharsets.UTF_8));
    return bytesToHex(hash);
}
4.3.3 JWT Token认证

java

复制代码
String token = Token.productToken(existUser);
existUser.setToken(token);

// Token生成
public static String productToken(User user) {
    String secret = user.getId() + user.getPassword() + System.currentTimeMillis();
    // 使用Base64编码
    return Base64.getEncoder().encodeToString(secret.getBytes());
}

五、关键技术难点与解决方案

5.1 消息去重与防重复转发

问题:同一消息可能被多次处理导致重复转发

解决方案

  1. 每个消息生成唯一ID(使用时间戳)

  2. 处理完成后从列表和文件中移除

  3. 使用Set集合收集待移除的ID

java

复制代码
Set<String> idsToRemove = new HashSet<>();
for (MergeRelation relation : mergeRelations) {
    // 处理逻辑...
    for (WxInfo originalInfo : relation.getOriginalInfos()) {
        if (originalInfo.getId() != null) {
            idsToRemove.add(originalInfo.getId());
        }
    }
}
// 批量移除
Constants.WX_INFO_LIST.removeIf(wxInfo -> 
    wxInfo.getId() != null && idsToRemove.contains(wxInfo.getId())
);

5.2 图片路径处理

问题:Windows路径中的反斜杠在JSON传输中需要转义

解决方案

java

复制代码
// 存储时使用双反斜杠
String imagePath = coze9Res.imageUrl.replaceAll("&&", "\\\\\\\\");

// 或者使用正斜杠统一路径
String savePath = Constants.IMAGE_SAVE_PATH + "/" + System.currentTimeMillis() + ".jpg";

5.3 大模型返回结果解析

问题:大模型返回的JSON可能包含非标准格式

解决方案

java

复制代码
ObjectMapper mapper = new ObjectMapper();
// 启用宽松模式
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
mapper.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);

5.4 消息超时处理

问题:消息超过5分钟未处理可能导致用户等待过久

解决方案

java

复制代码
long currentTime = System.currentTimeMillis() / 1000;
Map<Boolean, List<WxInfo>> partitioned = Constants.WX_INFO_LIST.stream()
    .collect(Collectors.partitioningBy(
        wxInfo -> (currentTime - wxInfo.getSendTime()) <= 300
    ));

// 有效数据保留,过期数据立即处理
List<WxInfo> validList = partitioned.get(true);
List<WxInfo> expiredList = partitioned.get(false);

六、系统优化建议

6.1 性能优化

  1. 批量数据库操作:使用批量插入代替逐条插入

  2. 异步处理:消息转发使用异步线程池

  3. 缓存优化:热点数据使用Redis缓存

6.2 可扩展性

  1. 消息类型扩展:支持更多企业微信消息类型

  2. 智能体扩展:支持对接多个大模型平台

  3. 转发策略扩展:支持条件转发、优先级转发等

6.3 监控与日志

  1. 消息处理链路追踪:记录每条消息的完整处理链路

  2. 异常告警:关键异常发送邮件或短信告警

  3. 性能指标:统计消息处理延迟、成功率等

七、总结

本文设计并实现了一套完整的企业微信消息接收与转发系统,通过Spring Boot后端、Vue前端、Python消息监听和Coze大模型的组合,实现了:

  1. 实时消息监听:支持文本、图片、位置等多种消息类型

  2. 智能消息聚合:减少大模型调用次数,降低API成本

  3. AI信息提取:从消息中自动提取车牌号、姓名、手机号等关键信息

  4. 灵活转发配置:可视化界面支持多对多转发关系配置

  5. 消息持久化:本地文件缓存保证消息不丢失

该系统已经在实际企业场景中投入使用,显著提升了客服响应效率和消息处理能力,为企业的数字化转型提供了有力支撑。

相关推荐
chenyulin454520 小时前
企业微信API二次开发:万级并发回调下的极致幂等性设计与防重放架构实战
大数据·人工智能·安全·架构·企业微信
梦想的旅途221 小时前
利用 API 实现企业微信消息自动化推送
运维·自动化·企业微信
小懿互联集成平台1 天前
企业微信与金蝶云星空业财审批一体化对接实施方案
数据分析·企业微信·金蝶云星空·小懿互联·数据集成对接·采购申请审批·费用报销审批
2501_941982051 天前
企业微信二下开发:自动发送图片让社群活动海报精准送达?
企业微信
chenyulin45451 天前
企业微信API:海量会话存档数据的高性能检索与Elasticsearch索引设计
大数据·人工智能·安全·企业微信
2501_941982051 天前
企业微信二次开发:私域数据基石——三大核心基础能力接口实战
windows·架构·bootstrap·企业微信
迷雾悠悠2 天前
企业微信iPad协议聚合聊天系统:从原理到实战开发指南
ios·企业微信·ipad
haidy ahmed2 天前
企微复杂审批流反序列化:动态表单解析引擎与EAV存储模型
数据库·人工智能·自动化·企业微信
喜欢踢足球的老罗2 天前
企业微信代开发应用组织架构同步踩坑实录
架构·企业微信·代开发应用