11 #4

Merged
pqmnl64u8 merged 18 commits from 郭雨露 into main 1 year ago

@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
SOFTWARE.

@ -1,195 +1,199 @@
<p align="center">
<a href="https://wx.xxccss.com/"><img src="image/logo.png" width="45%"></a>
</p>
<p align="center">
<strong>🍬Java版微信聊天记录备份与管理工具</strong>
</p>
<p align="center">
👉 <a href="https://wx.xxccss.com/">https://wx.xxccss.com/</a> 👈
</p>
<p align="center">
<a href="https://hellogithub.com/repository/5055dcceee434dc5851ac9897cb27396" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=5055dcceee434dc5851ac9897cb27396&claim_uid=AVv4KeNnZs2Ig3a" alt="FeaturedHelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /></a>
</p>
<p align="center">
<a href="https://github.com/xuchengsheng/spring-reading/stargazers"><img src="https://img.shields.io/github/stars/xuchengsheng/wx-dump-4j?logo=github&logoColor=%23EF2D5E&label=Stars&labelColor=%23000000&color=%23EF2D5E&cacheSeconds=3600" alt="Stars Badge"/></a>
<a href="https://github.com/xuchengsheng"><img src="https://img.shields.io/github/followers/xuchengsheng?label=Followers&logo=github&logoColor=%23FC521F&labelColor=%231A2477&color=%23FC521F&cacheSeconds=3600" alt="Follow Badge"></a>
<a href="https://github.com/xuchengsheng/wx-dump-4j/fork"><img src="https://img.shields.io/github/forks/xuchengsheng/wx-dump-4j?label=Forks&logo=github&logoColor=%23F2BB13&labelColor=%23BE2323&color=%23F2BB13" alt="Fork Badge"></a>
<a href="https://github.com/xuchengsheng/wx-dump-4j/watchers"><img src="https://img.shields.io/github/watchers/xuchengsheng/wx-dump-4j?label=Watchers&logo=github&logoColor=%23FF4655&labelColor=%234169E1&color=%23FF4655&cacheSeconds=3600" alt="Watchers Badge"></a>
</p>
<p align="center">
<img src="https://img.shields.io/badge/Java-11%2B-%23437291?logo=openjdk&logoColor=%23437291"/>
<img src="https://img.shields.io/badge/Spring-5.3.10-%23437291?logo=Spring&logoColor=%236DB33F&color=%236DB33F"/>
<img src="https://img.shields.io/badge/SpringBoot-2.5.5-%23437291?logo=SpringBoot&logoColor=%236DB33F&color=%236DB33F"/>
<img src="https://img.shields.io/badge/JNA-5.8.0-%23437291?logo=JNA&logoColor=%23228B22&color=%23228B22"/>
<img src="https://img.shields.io/badge/Hutool-5.8.16-%23437291?logo=JNA&logoColor=%23F08080&color=%23F08080"/>
<img src="https://img.shields.io/badge/easyexcel-5.8.16-%23437291?logo=JNA&logoColor=%23D2691E&color=%23D2691E"/>
<img src="https://img.shields.io/badge/protobuf-3.25.1-%23437291?logo=JNA&logoColor=%23800080&color=%23800080"/>
<img src="https://img.shields.io/badge/mapstruct-1.4.2-%23437291?logo=JNA&logoColor=%23DC143C&color=%23DC143C"/>
<img src="https://img.shields.io/badge/druid-1.2.20-%23437291?logo=JNA&logoColor=%23C71585&color=%23C71585"/>
<img src="https://img.shields.io/badge/mybatisPlus-3.5.4.1-%23437291?logo=JNA&logoColor=%234B0082&color=%234B0082"/>
<img src="https://img.shields.io/badge/sqlite-3.34.0-%23437291?logo=JNA&logoColor=%230000CD&color=%230000CD"/>
<img src="https://img.shields.io/badge/lombok-1.18.20-%23437291?logo=JNA&logoColor=%23008B8B&color=%23008B8B"/>
</p>
-------------------------------------------------------------------------------
## 📚 简介
wx-dump-4j是一款基于Java开发的微信数据分析工具。它准确显示好友数、群聊数和当日消息总量提供过去15天每日消息统计了解社交活跃度。识别展示最近一个月内互动频繁的前10位联系人。支持导出聊天记录、联系人、群聊信息及查看**超过三天限制的朋友圈**历史记录和**找回微信好友**。
## 💡 主要功能
- 👤 **获取用户信息**获取当前登录微信的详细信息包括昵称、账号、手机号、邮箱、秘钥、微信Id。
- 💬 **支持多种消息类型**:管理微信聊天对话中的文本、引用、图片、表情、卡片链接、系统消息等。
- 📊 **综合管理**:提供微信会话、联系人、群聊与朋友圈的全面管理功能。
- 📥 **记录导出**:支持导出微信聊天记录、联系人、已删除好友和群聊信息,便于备份和管理。
- 📅 **查看历史朋友圈**:突破三日限制,查看更久以前的朋友圈历史记录,方便回顾和管理。
- 📈 **微信统计功能**:展示微信好友数、群聊数及今日收发消息总量,了解社交活跃度。
- 📊 **消息统计**统计过去15天内每日微信消息数量掌握长期消息交流情况。
- 🔝 **互动联系人**展示最近一个月互动最频繁的前10位联系人了解重要社交联系。
- 🧩 **消息类别占比**:展示微信消息类别占比图表,分析不同类型消息的占比情况。
- ☁️ **关键字词云**:展示微信最近使用的关键字词云图,分析聊天内容重点。
- 🔄 **找回已删除好友**:支持找回已删除的微信好友,恢复重要联系人。
- 🖥️ **微信多开支持**:支持微信多开功能,方便管理多个账号,提高效率。
## 🚀 快速启动
本指南将帮助您快速启动并运行项目,无论是安装包部署还是本地部署。
### 环境准备
在开始之前,请确保您的开发环境满足以下要求:
- 安装 [Java](https://repo.huaweicloud.com/java/jdk/11.0.2+9/jdk-11.0.2_windows-x64_bin.exe),版本为 JDK 11+。
- 安装 [Node.js](https://nodejs.org/en/),版本为 18+。
- 安装 [Maven](https://maven.apache.org/download.cgi),版本为 3.5.0+。
- 选择一款开发工具,比如 IntelliJ IDEA。
### 二进制部署
- 点击下载最新版 [wx-dump-4j-bin.tar.gz](https://github.com/xuchengsheng/wx-dump-4j/releases/download/v1.1.0/wx-dump-4j-bin.tar.gz)。
- 解压缩 `wx-dump-4j-bin.tar.gz` 文件,并进入 `bin` 目录。
- 双击 `start.bat` 启动文件。
- 启动成功后,在浏览器中访问 [http://localhost:8080](http://localhost:8080) 以查看应用。
### 本地部署
- 下载源码:
```bash
$ git clone https://github.com/xuchengsheng/wx-dump-4j.git
```
- 安装后端依赖:
```bash
$ cd wx-dump-4j mvn clean install
```
- 使用开发工具(如 IntelliJ IDEA启动 com.xcs.wx.WxDumpApplication。
- 安装前端依赖:
```bash
$ cd wx-dump-ui npm install
```
- 启动前端服务:
```bash
$ npm run start
```
- 前端服务启动成功后,在浏览器中访问 http://localhost:8000 以查看应用。
## ⚡ 技术栈
以下是本项目使用的技术栈:
| 技术 | 描述 | 版本 |
|--------------|---------------------------|-----------|
| Spring Boot | Web 和 Thymeleaf 框架 | 2.7.15 |
| SQLite | 轻量级数据库 | 3.34.0 |
| Lombok | 简化 Java 代码 | 1.18.20 |
| MyBatis Plus | ORM 框架扩展 | 3.5.4.1 |
| Dynamic Datasource | 动态数据源管理 | 4.2.0 |
| Druid | 数据库连接池 | 1.2.20 |
| MapStruct | Java Bean 映射工具 | 1.4.2.Final |
| Hutool | Java 工具库 | 5.8.16 |
| JNA | Java 本地访问 | 5.8.0 |
| Protobuf | 序列化框架 | 3.25.1 |
| gRPC | RPC 框架 | 1.11.0 |
| EasyExcel | Excel 操作工具 | 3.3.3 |
| Commons Compress | 压缩和解压缩工具 | 1.19 |
| Jackson Dataformat XML | XML 解析工具 | 2.13.5 |
| Commons Lang3 | 常用工具类库 | 3.12.0 |
## ⛔️️ 使用限制
本软件仅适用于Windows操作系统。我们目前不支持macOS、Linux或其他操作系统。如果你在尝试在非Windows系统上运行本软件时可能遇到兼容性问题这些问题可能导致软件无法正常运行或产生其他意外后果。
| 操作系统 | 支持情况 |
|:--------:|:----------:|
| Windows | 支持 |
| macOS | 不支持 |
| Linux | 不支持 |
## ⚠️免责声明
本软件仅供技术研究和教育目的使用,旨在解密用户个人微信聊天记录。严禁将本软件用于任何非法目的,包括但不限于侵犯隐私权或非授权数据访问。作为软件开发者,我不对因使用或滥用本软件产生的任何形式的损失或损害承担责任。
## ⛵欢迎贡献!
如果你发现任何错误🔍或者有改进建议🛠️,欢迎提交 issue 或者 pull request。你的反馈📢对于我非常宝贵💎
## 💻我的 GitHub 统计
[![Star History Chart](https://api.star-history.com/svg?repos=xuchengsheng/wx-dump-4j&type=Date)](https://star-history.com/#xuchengsheng/wx-dump-4j&Date)
## 🎉Stargazers
[![Stargazers123 repo roster for @xuchengsheng/wx-dump-4j](https://reporoster.com/stars/xuchengsheng/wx-dump-4j)](https://github.com/xuchengsheng/wx-dump-4j/stargazers)
## 🎉Forkers
[![Forkers repo roster for @xuchengsheng/wx-dump-4j](https://reporoster.com/forks/xuchengsheng/wx-dump-4j)](https://github.com/xuchengsheng/wx-dump-4j/network/members)
## 🍱请我吃盒饭?
作者晚上还要写博客✍️,平时还需要工作💼,如果帮到了你可以请作者吃个盒饭🥡
<div>
<img alt="logo" src="image/WeChatPay.png" style="width: 240px;height: 260px">
<img alt="logo" src="image/Alipay.png" style="width: 240px;height: 260px">
</div>
## ⭐️扫码关注微信公众号
关注后,回复关键字📲 **加群**📲,即可加入我们的技术交流群,与更多开发者一起交流学习。
在此我们真诚地邀请您访问我们的GitHub项目页面如果您觉得***wx-dump-4j***对您有帮助,请顺手点个⭐️**Star**⭐️!每一颗星星都是我们前进的动力,是对我们努力的最大肯定。非常感谢您的支持!
<div>
<img alt="logo" src="image/wechat-mp.png" height="180px">>
</div>
## 👀 演示图
<table>
<tr>
<td><img src="image/screenshot/dashboard.png"/></td>
<td><img src="image/screenshot/session.png"/></td>
</tr>
<tr>
<td><img src="image/screenshot/contact.png"/></td>
<td><img src="image/screenshot/recover-contact.png"/></td>
</tr>
<tr>
<td><img src="image/screenshot/feeds.png"/></td>
<td><img src="image/screenshot/chat.png"/></td>
</tr>
<tr>
<td><img src="image/screenshot/chatroom.png"/></td>
<td><img src="image/screenshot/chatroom-detail.png"/></td>
</tr>
<tr>
<td><img src="image/screenshot/database.png"/></td>
<td><img src="image/screenshot/database-list.png"/></td>
</tr>
</table>
<p align="center">
<a href="https://wx.xxccss.com/"><img src="image/logo.png" width="45%"></a>
</p>
<p align="center">
<strong>🍬Java版微信聊天记录备份与管理工具</strong>
</p>
<p align="center">
👉 <a href="https://wx.xxccss.com/">https://wx.xxccss.com/</a> 👈
</p>
<p align="center">
<a href="https://hellogithub.com/repository/5055dcceee434dc5851ac9897cb27396" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=5055dcceee434dc5851ac9897cb27396&claim_uid=AVv4KeNnZs2Ig3a" alt="FeaturedHelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /></a>
</p>
<p align="center">
<a href="https://github.com/xuchengsheng/spring-reading/stargazers"><img src="https://img.shields.io/github/stars/xuchengsheng/wx-dump-4j?logo=github&logoColor=%23EF2D5E&label=Stars&labelColor=%23000000&color=%23EF2D5E&cacheSeconds=3600" alt="Stars Badge"/></a>
<a href="https://github.com/xuchengsheng"><img src="https://img.shields.io/github/followers/xuchengsheng?label=Followers&logo=github&logoColor=%23FC521F&labelColor=%231A2477&color=%23FC521F&cacheSeconds=3600" alt="Follow Badge"></a>
<a href="https://github.com/xuchengsheng/wx-dump-4j/fork"><img src="https://img.shields.io/github/forks/xuchengsheng/wx-dump-4j?label=Forks&logo=github&logoColor=%23F2BB13&labelColor=%23BE2323&color=%23F2BB13" alt="Fork Badge"></a>
<a href="https://github.com/xuchengsheng/wx-dump-4j/watchers"><img src="https://img.shields.io/github/watchers/xuchengsheng/wx-dump-4j?label=Watchers&logo=github&logoColor=%23FF4655&labelColor=%234169E1&color=%23FF4655&cacheSeconds=3600" alt="Watchers Badge"></a>
</p>
<p align="center">
<img src="https://img.shields.io/badge/Java-11%2B-%23437291?logo=openjdk&logoColor=%23437291"/>
<img src="https://img.shields.io/badge/Spring-5.3.10-%23437291?logo=Spring&logoColor=%236DB33F&color=%236DB33F"/>
<img src="https://img.shields.io/badge/SpringBoot-2.5.5-%23437291?logo=SpringBoot&logoColor=%236DB33F&color=%236DB33F"/>
<img src="https://img.shields.io/badge/JNA-5.8.0-%23437291?logo=JNA&logoColor=%23228B22&color=%23228B22"/>
<img src="https://img.shields.io/badge/Hutool-5.8.16-%23437291?logo=JNA&logoColor=%23F08080&color=%23F08080"/>
<img src="https://img.shields.io/badge/easyexcel-5.8.16-%23437291?logo=JNA&logoColor=%23D2691E&color=%23D2691E"/>
<img src="https://img.shields.io/badge/protobuf-3.25.1-%23437291?logo=JNA&logoColor=%23800080&color=%23800080"/>
<img src="https://img.shields.io/badge/mapstruct-1.4.2-%23437291?logo=JNA&logoColor=%23DC143C&color=%23DC143C"/>
<img src="https://img.shields.io/badge/druid-1.2.20-%23437291?logo=JNA&logoColor=%23C71585&color=%23C71585"/>
<img src="https://img.shields.io/badge/mybatisPlus-3.5.4.1-%23437291?logo=JNA&logoColor=%234B0082&color=%234B0082"/>
<img src="https://img.shields.io/badge/sqlite-3.34.0-%23437291?logo=JNA&logoColor=%230000CD&color=%230000CD"/>
<img src="https://img.shields.io/badge/lombok-1.18.20-%23437291?logo=JNA&logoColor=%23008B8B&color=%23008B8B"/>
</p>
## 📚 简介
wx-dump-4j是一款基于Java开发的微信数据分析工具。它准确显示好友数、群聊数和当日消息总量提供过去15天每日消息统计了解社交活跃度。识别展示最近一个月内互动频繁的前10位联系人。支持导出聊天记录、联系人、群聊信息及查看**超过三天限制的朋友圈**历史记录和**找回微信好友**。
## 💡 主要功能
- 👤 **获取用户信息**获取当前登录微信的详细信息包括昵称、账号、手机号、邮箱、秘钥、微信Id。
- 💬 **支持多种消息类型**:管理微信聊天对话中的文本、引用、图片、表情、卡片链接、系统消息等。
- 📊 **综合管理**:提供微信会话、联系人、群聊与朋友圈的全面管理功能。
- 📥 **记录导出**:支持导出微信聊天记录、联系人、已删除好友和群聊信息,便于备份和管理。
- 📅 **查看历史朋友圈**:突破三日限制,查看更久以前的朋友圈历史记录,方便回顾和管理。
- 📈 **微信统计功能**:展示微信好友数、群聊数及今日收发消息总量,了解社交活跃度。
- 📊 **消息统计**统计过去15天内每日微信消息数量掌握长期消息交流情况。
- 🔝 **互动联系人**展示最近一个月互动最频繁的前10位联系人了解重要社交联系。
- 🧩 **消息类别占比**:展示微信消息类别占比图表,分析不同类型消息的占比情况。
- ☁️ **关键字词云**:展示微信最近使用的关键字词云图,分析聊天内容重点。
- 🔄 **找回已删除好友**:支持找回已删除的微信好友,恢复重要联系人。
- 🖥️ **微信多开支持**:支持微信多开功能,方便管理多个账号,提高效率。
## 🚀 快速启动
本指南将帮助您快速启动并运行项目,无论是安装包部署还是本地部署。
### 环境准备
在开始之前,请确保您的开发环境满足以下要求:
- 安装 [Java](https://repo.huaweicloud.com/java/jdk/11.0.2+9/jdk-11.0.2_windows-x64_bin.exe),版本为 JDK 11+。
- 安装 [Node.js](https://nodejs.org/en/),版本为 18+。
- 安装 [Maven](https://maven.apache.org/download.cgi),版本为 3.5.0+。
- 选择一款开发工具,比如 IntelliJ IDEA。
### 二进制部署
- 点击下载最新版 [wx-dump-4j-bin.tar.gz](https://github.com/xuchengsheng/wx-dump-4j/releases/download/v1.1.0/wx-dump-4j-bin.tar.gz)。
- 解压缩 `wx-dump-4j-bin.tar.gz` 文件,并进入 `bin` 目录。
- 双击 `start.bat` 启动文件。
- 启动成功后,在浏览器中访问 [http://localhost:8080](http://localhost:8080) 以查看应用。
### 本地部署
- 下载源码:
```bash
$ git clone https://github.com/xuchengsheng/wx-dump-4j.git
```
- 安装后端依赖:
```bash
$ cd wx-dump-4j mvn clean install
```
- 使用开发工具(如 IntelliJ IDEA启动 com.xcs.wx.WxDumpApplication。
- 安装前端依赖:
```bash
$ cd wx-dump-ui npm install
```
- 启动前端服务:
```bash
$ npm run start
```
- 前端服务启动成功后,在浏览器中访问 http://localhost:8000 以查看应用。
## ⚡ 技术栈
以下是本项目使用的技术栈:
| 技术 | 描述 | 版本 |
|--------------|---------------------------|-----------|
| Spring Boot | Web 和 Thymeleaf 框架 | 2.7.15 |
| SQLite | 轻量级数据库 | 3.34.0 |
| Lombok | 简化 Java 代码 | 1.18.20 |
| MyBatis Plus | ORM 框架扩展 | 3.5.4.1 |
| Dynamic Datasource | 动态数据源管理 | 4.2.0 |
| Druid | 数据库连接池 | 1.2.20 |
| MapStruct | Java Bean 映射工具 | 1.4.2.Final |
| Hutool | Java 工具库 | 5.8.16 |
| JNA | Java 本地访问 | 5.8.0 |
| Protobuf | 序列化框架 | 3.25.1 |
| gRPC | RPC 框架 | 1.11.0 |
| EasyExcel | Excel 操作工具 | 3.3.3 |
| Commons Compress | 压缩和解压缩工具 | 1.19 |
| Jackson Dataformat XML | XML 解析工具 | 2.13.5 |
| Commons Lang3 | 常用工具类库 | 3.12.0 |
## ⛔️️ 使用限制
本软件仅适用于Windows操作系统。我们目前不支持macOS、Linux或其他操作系统。如果你在尝试在非Windows系统上运行本软件时可能遇到兼容性问题这些问题可能导致软件无法正常运行或产生其他意外后果。
| 操作系统 | 支持情况 |
|:--------:|:----------:|
| Windows | 支持 |
| macOS | 不支持 |
| Linux | 不支持 |
## ⚠️免责声明
本软件仅供技术研究和教育目的使用,旨在解密用户个人微信聊天记录。严禁将本软件用于任何非法目的,包括但不限于侵犯隐私权或非授权数据访问。作为软件开发者,我不对因使用或滥用本软件产生的任何形式的损失或损害承担责任。
## ⛵欢迎贡献!
如果你发现任何错误🔍或者有改进建议🛠️,欢迎提交 issue 或者 pull request。你的反馈📢对于我非常宝贵💎
## 💻我的 GitHub 统计
[![Star History Chart](https://api.star-history.com/svg?repos=xuchengsheng/wx-dump-4j&type=Date)](https://star-history.com/#xuchengsheng/wx-dump-4j&Date)
## 🎉Stargazers
[![Stargazers123 repo roster for @xuchengsheng/wx-dump-4j](https://reporoster.com/stars/xuchengsheng/wx-dump-4j)](https://github.com/xuchengsheng/wx-dump-4j/stargazers)
## 🎉Forkers
[![Forkers repo roster for @xuchengsheng/wx-dump-4j](https://reporoster.com/forks/xuchengsheng/wx-dump-4j)](https://github.com/xuchengsheng/wx-dump-4j/network/members)
## 🍱请我吃盒饭?
作者晚上还要写博客✍️,平时还需要工作💼,如果帮到了你可以请作者吃个盒饭🥡
<div>
<img alt="logo" src="image/WeChatPay.png" style="width: 240px;height: 260px">
<img alt="logo" src="image/Alipay.png" style="width: 240px;height: 260px">
</div>
## ⭐️扫码关注微信公众号
关注后,回复关键字📲 **加群**📲,即可加入我们的技术交流群,与更多开发者一起交流学习。
在此我们真诚地邀请您访问我们的GitHub项目页面如果您觉得***wx-dump-4j***对您有帮助,请顺手点个⭐️**Star**⭐️!每一颗星星都是我们前进的动力,是对我们努力的最大肯定。非常感谢您的支持!
<div>
<img alt="logo" src="image/wechat-mp.png" height="180px">>
</div>
## 👀 演示图
<table>
<tr>
<td><img src="image/screenshot/dashboard.png"/></td>
<td><img src="image/screenshot/session.png"/></td>
</tr>
<tr>
<td><img src="image/screenshot/contact.png"/></td>
<td><img src="image/screenshot/recover-contact.png"/></td>
</tr>
<tr>
<td><img src="image/screenshot/feeds.png"/></td>
<td><img src="image/screenshot/chat.png"/></td>
</tr>
<tr>
<td><img src="image/screenshot/chatroom.png"/></td>
<td><img src="image/screenshot/chatroom-detail.png"/></td>
</tr>
<tr>
<td><img src="image/screenshot/database.png"/></td>
<td><img src="image/screenshot/database-list.png"/></td>
</tr>
</table>
=======
# wx-dump-4j
>>>>>>> c4b6449ae2686772c4ab318ba75389b6a4df21ea

@ -3,122 +3,162 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!-- Maven 项目对象模型POM的版本号通常固定为 4.0.0,表示遵循的 POM 规范版本 -->
<modelVersion>4.0.0</modelVersion>
<!-- 项目的groupId是项目在 Maven 仓库中的唯一标识,一般采用反向域名的格式,用于区分不同组织或公司下的项目 -->
<groupId>com.xcs.wx</groupId>
<!-- 项目的artifactId是项目在同一 groupId 下的唯一标识,相当于项目的名称,与 groupId 一起构成项目在 Maven 仓库中的坐标 -->
<artifactId>wx-dump-4j</artifactId>
<!-- 项目的打包类型,这里设置为 "pom",表示这是一个聚合项目或者父项目,本身不会生成可部署的构件(如 jar 包、war 包等),
而是用于管理子项目以及统一配置依赖等信息 -->
<packaging>pom</packaging>
<!-- 项目的版本号,这里使用了一个属性(${revision})来定义,后续可以在 properties 元素中对该属性进行赋值 -->
<version>${revision}</version>
<!-- 定义项目包含的子模块,这些子模块会作为当前项目的一部分被统一管理,例如在构建时可以一起构建等 -->
<modules>
<!-- 第一个子模块,模块名称为 "wx-dump-admin"Maven 会根据配置去查找对应的子项目目录并进行相关构建操作 -->
<module>wx-dump-admin</module>
<!-- 第二个子模块,模块名称为 "wx-dump-dist",同样会被纳入当前项目的管理范畴 -->
<module>wx-dump-dist</module>
</modules>
<!-- 定义项目中使用的各种属性,这些属性可以在项目的其他地方通过 ${属性名} 的方式进行引用 -->
<properties>
<!-- 指定项目编译时使用的 Java 版本,这里设置源文件和目标文件的编译版本都为 11 -->
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<!-- 指定 Maven Assembly 插件的版本号 -->
<maven-assembly-plugin.version>3.5.0</maven-assembly-plugin.version>
<!-- 指定项目构建时源文件的编码格式为 UTF-8 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 对之前版本号中使用的 ${revision} 属性进行赋值,这里设置项目的版本为 1.1.0 -->
<revision>1.1.0</revision>
</properties>
<!-- 依赖管理部分,用于统一管理项目及其子项目所依赖的各种外部库的版本等信息,
子项目可以继承这里定义的依赖配置,但不一定会自动引入这些依赖(具体是否引入要看子项目的依赖配置) -->
<dependencyManagement>
<dependencies>
<!-- 引入 Spring Boot 的 Web 启动器依赖,指定版本为 2.7.15,该依赖包含构建 Web 应用所需的一系列基础依赖,
方便快速搭建基于 Spring Boot 的 Web 项目 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.15</version>
</dependency>
<!-- 引入 Spring Boot 的 Thymeleaf 启动器依赖,版本为 2.7.15,用于在 Spring Boot 项目中集成 Thymeleaf 模板引擎,
实现页面视图的渲染 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.7.15</version>
</dependency>
<!-- 引入 SQLite 的 JDBC 驱动依赖,版本是 3.34.0,用于在项目中连接和操作 SQLite 数据库 -->
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.34.0</version>
</dependency>
<!-- 引入 Lombok 依赖,版本为 1.18.20Lombok 可以通过注解方式简化 Java 代码,自动生成诸如 getter、setter、构造函数等方法 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<!-- 引入 MyBatis Plus 的 Spring Boot 启动器依赖,版本 3.5.4.1MyBatis Plus 是 MyBatis 的增强工具,
提供通用的 CRUD 操作等便捷功能,便于数据库访问层开发 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.4.1</version>
</dependency>
<!-- 引入动态数据源的 Spring Boot 启动器依赖,版本 4.2.0,用于实现项目中动态切换数据源的功能 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>4.2.0</version>
</dependency>
<!-- 引入 Druid 的 Spring Boot 启动器依赖,版本 1.2.20Druid 是性能优秀的数据库连接池,还具备监控等功能 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.20</version>
</dependency>
<!-- 引入 MapStruct 的核心依赖,版本 1.4.2.FinalMapStruct 用于生成类型安全、高性能且遵循 Java 规范的 bean 映射代码 -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.4.2.Final</version>
</dependency>
<!-- 引入 MapStruct 的处理器依赖,版本 1.4.2.Final用于在编译阶段处理 MapStruct 注解,生成相应的映射代码 -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.4.2.Final</version>
</dependency>
<!-- 引入 Hutool 工具集依赖,版本 5.8.16Hutool 提供大量实用工具类,涵盖字符串处理、文件操作、日期时间处理等多方面 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>
<!-- 引入 JNAJava Native Access核心依赖版本 5.8.0,它允许 Java 程序调用本地代码库,便于与底层系统交互 -->
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.8.0</version>
</dependency>
<!-- 引入 JNA 平台相关依赖,版本 5.8.0,提供特定平台下的扩展功能 -->
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>5.8.0</version>
</dependency>
<!-- 引入 Google 的 Protocol Buffersprotobuf核心依赖版本 3.25.1protobuf 用于数据序列化和通信协议等场景 -->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.25.1</version>
</dependency>
<!-- 引入 Google 的 Protocol Buffersprotobuf工具类依赖版本 3.25.1,提供方便操作 protobuf 数据的实用方法 -->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>3.25.1</version>
</dependency>
<!-- 引入 gRPC 相关的所有依赖,版本 1.11.0gRPC 是高性能 RPC 框架,常用于微服务间通信 -->
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-all</artifactId>
<version>1.11.0</version>
</dependency>
<!-- 引入 EasyExcel 依赖,版本 3.3.3,用于方便地操作 Excel 文件 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.3.3</version>
</dependency>
<!-- 引入 Commons Compress 依赖,版本 1.19,用于操作各种压缩格式文件 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.19</version>
</dependency>
<!-- 引入 Jackson 的 XML 数据格式模块依赖,版本 2.13.5,用于支持对象与 XML 数据的序列化和反序列化 -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.13.5</version>
</dependency>
<!-- 引入 Commons Lang3 依赖,版本 3.12.0,提供大量对 Java 基本数据类型、字符串等操作的实用工具方法 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<!-- 引入名为 "wx-dump-admin" 的项目作为依赖,版本使用之前定义的 ${revision} 属性值,
通常表示当前项目与该子项目之间存在某种关联,比如依赖其提供的功能等 -->
<dependency>
<groupId>com.xcs.wx</groupId>
<artifactId>wx-dump-admin</artifactId>

@ -2,6 +2,8 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!-- 定义该项目的父项目相关信息,通过这些配置,当前项目可以继承父项目的一些配置和依赖等内容 -->
<parent>
<artifactId>wx-dump-4j</artifactId>
<groupId>com.xcs.wx</groupId>
@ -9,92 +11,123 @@
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<!-- 当前项目的构件标识符,也就是项目生成的 jar 包等构件的名称 -->
<artifactId>wx-dump-admin</artifactId>
<!-- 项目的打包方式,这里设置为 "jar",表示最终会打包成一个 Java 可执行的 jar 文件 -->
<packaging>jar</packaging>
<!-- 项目依赖配置部分,在这里列出了项目运行所需要依赖的其他库 -->
<dependencies>
<!-- 引入 Spring Boot 的 Web 启动器依赖,它包含了构建 Web 应用所需的一系列基础依赖,
例如 Spring MVC 等,方便快速搭建基于 Spring Boot 的 Web 项目 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入 Spring Boot 的 Thymeleaf 启动器依赖,用于在 Spring Boot 项目中集成 Thymeleaf 模板引擎,
方便进行页面视图的渲染 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- 引入 SQLite 的 JDBC 驱动依赖,用于在项目中连接和操作 SQLite 数据库 -->
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
</dependency>
<!-- 引入 Lombok 依赖Lombok 可以通过注解的方式帮助简化 Java 代码,例如自动生成 getter、setter、构造函数等方法 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- 引入 MyBatis Plus 的 Spring Boot 启动器依赖MyBatis Plus 是 MyBatis 的增强工具,
提供了很多便捷的功能,如通用的 CRUD 操作等,方便数据库访问层的开发 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!-- 引入动态数据源的 Spring Boot 启动器依赖,用于在项目中实现动态切换数据源的功能 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
</dependency>
<!-- 引入 Druid 的 Spring Boot 启动器依赖Druid 是一款性能优秀的数据库连接池,同时还具备监控等功能 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<!-- 引入 MapStruct 的核心依赖MapStruct 是一个用于生成类型安全、高性能且遵循 Java 规范的 bean 映射代码的注解处理器 -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
</dependency>
<!-- 引入 MapStruct 的处理器依赖,用于在编译阶段处理 MapStruct 的注解,生成相应的映射代码 -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
</dependency>
<!-- 引入 Hutool 工具集依赖Hutool 提供了大量实用的工具类,涵盖了字符串处理、文件操作、日期时间处理等多个方面,方便日常开发 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<!-- 引入 JNAJava Native Access核心依赖它允许 Java 程序调用本地代码库,方便与底层系统进行交互 -->
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
</dependency>
<!-- 引入 JNA 平台相关依赖,提供了特定平台下的一些扩展功能 -->
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
</dependency>
<!-- 引入 Google 的 Protocol Buffersprotobuf核心依赖protobuf 是一种轻便高效的结构化数据存储格式,
常用于数据序列化和通信协议等场景 -->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
</dependency>
<!-- 引入 Google 的 Protocol Buffersprotobuf工具类依赖提供了一些方便操作 protobuf 数据的实用方法 -->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
</dependency>
<!-- 引入 gRPC 相关的所有依赖gRPC 是一个高性能、开源和通用的 RPC 框架,基于 HTTP/2 协议实现,
常用于微服务之间的通信 -->
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-all</artifactId>
</dependency>
<!-- 引入 EasyExcel 依赖EasyExcel 是一个方便操作 Excel 文件的 Java 库,支持读写 Excel 等功能 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
</dependency>
<!-- 引入 Commons Compress 依赖,它提供了对各种压缩格式文件(如 ZIP、GZIP 等)进行操作的功能 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
</dependency>
<!-- 引入 Jackson 的 XML 数据格式模块依赖,用于在项目中支持将对象序列化为 XML 格式以及反序列化 XML 数据为对象 -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<!-- 引入 Commons Lang3 依赖,它提供了大量对 Java 基本数据类型、字符串、数组等进行操作的实用工具方法 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>
<!-- 项目构建配置部分,主要配置项目构建过程中使用的插件等相关信息 -->
<build>
<!-- 定义项目最终生成的构件(如 jar 包等)的名称 -->
<finalName>wx-dump-admin</finalName>
<plugins>
<!-- 配置 Maven 编译器插件,用于指定项目编译时使用的 Java 版本 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
@ -107,5 +140,4 @@
</plugins>
</build>
</project>

@ -7,109 +7,147 @@ import lombok.Data;
import org.apache.ibatis.type.ByteArrayTypeHandler;
/**
*
*
* ChatRoom
* 便
* @author xcs
* @date 20240108 0945
* &#064;date 20240108 0945
**/
@Data
// @Data注解由Lombok库提供它会自动为这个类生成一系列实用的方法具体如下
// - 自动生成所有私有属性对应的getter方法像通过调用getChatRoomName()、getUserNameList()等方法,外部代码可以方便地获取类中各个属性的值,
// 在需要访问群聊的具体属性信息时比如查看群聊名称、获取群聊成员用户名列表等这些getter方法能提供便捷的数据访问途径便于后续业务逻辑使用这些数据。
// - 自动生成所有私有属性对应的setter方法使得外部代码能够根据业务需求动态地修改对象的属性值例如当群聊的显示名称列表发生变化
// 可以通过调用setDisplayNameList(String newDisplayNameList)方法来更新displayNameList属性的值从而保证对象的属性能够灵活地反映群聊相关信息的实际变化情况增强了属性的可操作性。
// - 生成toString方法该方法能将ChatRoom对象以一种直观、易于阅读的字符串形式展示出来通常会包含类名以及各个属性的值
// 在调试程序时通过打印对象的toString结果可以快速查看当前群聊对象的具体状态了解各个属性的取值情况便于排查问题。
// - 生成hashCode方法在将对象存储到基于哈希的集合如HashMap、HashSet等中时会用到这个方法
// 它依据对象的属性值计算出一个唯一的哈希码,用于确定对象在哈希集合中的存储位置,方便在集合中快速查找和比较对象。
// - 生成equals方法用于比较两个ChatRoom对象是否在逻辑上相等也就是判断它们的所有属性值是否都完全相同
// 在涉及群聊对象比较的业务逻辑中(如判断两个群聊的配置是否一致等情况),该方法能准确地进行对象的相等性判断。
// 通过使用@Data注解大大减少了手动编写这些常规方法的工作量让代码更加简洁、易读且易于维护。
@TableName(value = "ChatRoom", autoResultMap = true)
// @TableName注解来自于MyBatis Plus框架用于指定该实体类对应的数据库表名这里表明ChatRoom类对应的数据库表名为"ChatRoom"。
// 而autoResultMap = true这个配置表示自动构建结果映射方便在查询数据库返回结果时能自动将结果集的数据映射到该类的属性上
// 减少了手动配置结果映射的繁琐过程,特别是当表结构和类结构有一定对应关系时,能更便捷地进行数据库与实体类之间的数据交互。
public class ChatRoom {
/**
*
* String
// 在整个系统中,不同的群聊应该具有不同的名称,通过这个名称可以在数据库操作(如查询、更新、删除等)以及业务逻辑处理中准确地定位到具体的群聊,
// 同时在用户界面展示群聊列表等场景下,也是用户识别不同群聊的重要依据之一。
*/
@TableId("ChatRoomName")
// @TableId注解用于指定该属性对应的数据库表中的主键字段名这里表明在数据库表"ChatRoom"中,主键字段名为"ChatRoomName"
// 即将类中的chatRoomName属性与数据库表中的主键列进行了关联确保了在数据库操作时能根据这个主键进行准确的记录定位和操作。
private String chatRoomName;
/**
*
* 使String
// 例如用逗号隔开各个用户名等形式,方便在需要获取群聊成员、进行成员相关的业务逻辑判断(如判断某个用户是否在群聊中)以及与其他系统模块交互传递成员信息等场景下使用。
*/
@TableField("UserNameList")
// @TableField注解用于指定该属性对应的数据库表中的字段名这里表示在数据库表"ChatRoom"中,该属性对应名为"UserNameList"的字段,
// 明确了类属性与数据库表字段之间的映射关系,确保数据的正确存储和读取。
private String userNameList;
/**
*
*
// 与用户名不同,显示名称可能更具个性化、友好化,方便在群聊界面展示成员信息时使用,其存储格式可能和用户名列表类似,也是按照一定规则拼接的字符串形式,
// 用于在展示群聊成员、进行成员显示相关的业务处理(如更新成员显示名称等)场景中发挥作用。
*/
@TableField("DisplayNameList")
private String displayNameList;
/**
* 0
* 0使Integer
// 具体含义取决于业务的具体定义例如可以用不同的整数值来区分普通群聊、加密群聊、临时群聊等不同类型的群聊初始默认值为0在创建群聊或者初始化相关数据时会用到这个默认值
// 后续可根据业务需求对其进行修改和判断,以实现不同的业务逻辑处理。
*/
@TableField("ChatRoomFlag")
private Integer chatRoomFlag;
/**
* 0
* 0
// 在涉及群聊权限管理如只有拥有者能进行某些特定操作像修改群聊设置等、群聊归属判断以及相关业务逻辑中起着关键作用初始默认值为0
// 当创建群聊时会确定具体的拥有者标识并进行相应赋值,后续也可以根据业务规则对其进行更新和查询等操作。
*/
@TableField("Owner")
private Integer owner;
/**
* 0
* 0
// 例如值为1时表示显示成员的显示名称值为0则不显示方便根据不同的业务场景或者用户偏好来设置群聊成员名称的展示情况在群聊界面展示相关的业务逻辑中会用到这个标志进行判断和处理。
*/
@TableField("IsShowName")
private Integer isShowName;
/**
*
*
// 用于在群聊中让其他成员识别自己,与前面的显示名称列表有所不同,它特指当前用户自己在该群聊中的展示名称,在群聊交互、展示自身信息等场景中发挥作用。
*/
@TableField("SelfDisplayName")
private String selfDisplayName;
/**
* 1
* 1
// 目前可能暂时没有具体的使用场景,但当后续需要增加新的属性或者功能时,可以利用这些预留字段进行扩展,避免了频繁修改数据库表结构和实体类结构带来的复杂性和风险。
*/
@TableField("Reserved1")
private Integer reserved1;
/**
* 2
* 21
// 具体内容和用途会根据未来业务发展的需求来确定。
*/
@TableField("Reserved2")
private String reserved2;
/**
* 3
* 3使使
*/
@TableField("Reserved3")
private Integer reserved3;
/**
* 4
* 4便
*/
@TableField("Reserved4")
private String reserved4;
/**
* 5
* 5使
*/
@TableField("Reserved5")
private Integer reserved5;
/**
* 6
* 6
*/
@TableField("Reserved6")
private String reserved6;
/**
* BLOB
* BLOBBinary Large Object使byte[]
// 这种形式常用于存储一些比较复杂、非结构化或者二进制格式的数据,比如群聊的一些特殊配置信息、历史聊天记录的二进制备份等,
// 通过指定typeHandler = ByteArrayTypeHandler.class使用字节数组类型处理器来处理该字段与数据库之间的数据转换确保二进制数据能够正确地在数据库中存储和读取
// 满足一些特殊的业务数据存储需求,特别是当数据不适合用常规的文本或简单数值类型表示时,就可以利用这个字段进行存储。
*/
@TableField(value = "RoomData", typeHandler = ByteArrayTypeHandler.class)
private byte[] roomData;
/**
* 7
* 7使
*/
@TableField("Reserved7")
private Integer reserved7;
/**
* 8
* 8
*/
@TableField("Reserved8")
private String reserved8;
}
}

@ -6,96 +6,130 @@ import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
*
*
* ChatRoomInfo
*
* 便
* @author xcs
* @date 20240109 1453
* &#064;date 20240109 1453
**/
@Data
// @Data注解由Lombok库提供它会自动为这个类生成一系列实用的方法具体如下
// - 自动生成所有私有属性对应的getter方法像通过调用getChatRoomName()、getAnnouncement()等方法,外部代码可以方便地获取类中各个属性的值,
// 在需要访问群聊信息的具体属性信息时比如查看群聊名称、获取群聊公告内容等这些getter方法能提供便捷的数据访问途径便于后续业务逻辑使用这些数据。
// - 自动生成所有私有属性对应的setter方法使得外部代码能够根据业务需求动态地修改对象的属性值例如当群聊公告内容发生变化
// 可以通过调用setAnnouncement(String newAnnouncement)方法来更新announcement属性的值从而保证对象的属性能够灵活地反映群聊信息的实际变化情况增强了属性的可操作性。
// - 生成toString方法该方法能将ChatRoomInfo对象以一种直观、易于阅读的字符串形式展示出来通常会包含类名以及各个属性的值
// 在调试程序时通过打印对象的toString结果可以快速查看当前群聊信息对象的具体状态了解各个属性的取值情况便于排查问题。
// - 生成hashCode方法在将对象存储到基于哈希的集合如HashMap、HashSet等中时会用到这个方法
// 它依据对象的属性值计算出一个唯一的哈希码,用于确定对象在哈希集合中的存储位置,方便在集合中快速查找和比较对象。
// - 生成equals方法用于比较两个ChatRoomInfo对象是否在逻辑上相等也就是判断它们的所有属性值是否都完全相同
// 在涉及群聊信息对象比较的业务逻辑中(如判断两个群聊的信息是否一致等情况),该方法能准确地进行对象的相等性判断。
// 通过使用@Data注解大大减少了手动编写这些常规方法的工作量让代码更加简洁、易读且易于维护。
@TableName("ChatRoomInfo")
// @TableName注解来自MyBatis Plus框架用于指定该实体类对应的数据库表名这里表明ChatRoomInfo类对应的数据库表名为"ChatRoomInfo"
// 明确了该类与数据库表之间的映射关系,方便后续进行数据库操作(如数据的插入、查询、更新、删除等)时能准确地找到对应的表,确保数据的正确交互。
public class ChatRoomInfo {
/**
*
* String
// 在整个系统中,不同的群聊应该具有不同的名称,通过这个名称可以在数据库操作(如查询、更新、删除等)以及业务逻辑处理中准确地定位到具体的群聊,
// 同时在用户界面展示群聊列表、查看群聊详情等场景下,也是用户识别不同群聊的重要依据之一,并且作为主键,它在数据库表的关联、索引等操作中起着核心作用。
*/
@TableId("ChatRoomName")
// @TableId注解用于指定该属性对应的数据库表中的主键字段名这里表明在数据库表"ChatRoomInfo"中,主键字段名为"ChatRoomName"
// 即将类中的chatRoomName属性与数据库表中的主键列进行了关联确保了在数据库操作时能根据这个主键进行准确的记录定位和操作保证数据的完整性和一致性。
private String chatRoomName;
/**
*
* String
// 在群聊界面展示公告板块或者成员查看群聊相关规定等场景中会展示这个公告内容,并且可以通过相应的业务逻辑对其进行编辑、更新操作,方便群聊的管理和信息传达。
*/
@TableField("Announcement")
// @TableField注解用于指定该属性对应的数据库表中的字段名这里表示在数据库表"ChatRoomInfo"中,该属性对应名为"Announcement"的字段,
// 明确了类属性与数据库表字段之间的映射关系,确保数据的正确存储和读取,便于与数据库进行交互来获取和修改公告内容信息。
private String announcement;
/**
* 0
* 0使Integer
// 每次对群聊相关重要信息进行修改时,可以递增这个版本号,通过比较版本号可以判断不同成员所看到的群聊信息是否是最新的,
// 也有助于在一些数据同步、历史记录查看以及版本管理相关的业务逻辑中发挥作用初始默认值为0方便在创建群聊或者首次设置相关信息时进行初始化操作。
*/
@TableField("InfoVersion")
private Integer infoVersion;
/**
*
* String
// 在需要追溯公告来源、查看谁有权限修改公告以及进行相关的操作记录查询等业务场景中,公告编辑者属性起着重要作用,便于对群聊公告的编辑历史和责任归属进行管理。
*/
@TableField("AnnouncementEditor")
private String announcementEditor;
/**
* 0
* 0Long19701100:00:00 UTC
// 到公告实际发布时刻所经过的毫秒数或者秒数(具体取决于系统的时间精度设定),通过这个时间戳,可以准确判断公告的时效性、进行公告的排序展示(按照发布时间先后顺序),
// 以及在一些基于时间范围的查询如查看某一时间段内发布的公告等业务场景中发挥作用初始默认值为0在发布公告时会更新为实际的发布时间戳值。
*/
@TableField("AnnouncementPublishTime")
private Long announcementPublishTime;
/**
* 0
* 0Integer
// 例如可以用不同的整数值来区分群聊正常、群聊被封禁、群聊维护中等等不同的状态情况初始默认值为0在创建群聊或者进行群聊状态变更操作时会用到这个默认值
// 并且可以根据业务需求对其进行修改和判断,以实现不同的业务逻辑处理,比如根据群聊状态决定是否允许成员发送消息等操作。
*/
@TableField("ChatRoomStatus")
private Integer chatRoomStatus;
/**
* 1
* 1Integer
// 目前可能暂时没有具体的使用场景,但当后续需要增加新的属性或者功能时,可以利用这些预留字段进行扩展,避免了频繁修改数据库表结构和实体类结构带来的复杂性和风险。
*/
@TableField("Reserved1")
private Integer reserved1;
/**
* 2
* 2String1
// 具体内容和用途会根据未来业务发展的需求来确定。
*/
@TableField("Reserved2")
private String reserved2;
/**
* 3
* 3使Integer使
*/
@TableField("Reserved3")
private Integer reserved3;
/**
* 4
* 4String便
*/
@TableField("Reserved4")
private String reserved4;
/**
* 5
* 5Integer使
*/
@TableField("Reserved5")
private Integer reserved5;
/**
* 6
* 6String
*/
@TableField("Reserved6")
private String reserved6;
/**
* 7
* 7Integer使
*/
@TableField("Reserved7")
private Integer reserved7;
/**
* 8
* 8String
*/
@TableField("Reserved8")
private String reserved8;
}
}

@ -4,201 +4,254 @@ import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.apache.ibatis.type.ByteArrayTypeHandler;
/**
*
*
* Contact
* 便
* @author xcs
* @date 20231222 1059
* &#064;date 20231222 1059
**/
@Data
@TableName(value = "Contact",autoResultMap = true)
// @Data注解由Lombok库提供它会自动为这个类生成一系列实用的方法具体作用如下
// - 自动生成所有私有属性对应的getter方法例如通过调用getUserName()、getAlias()等方法,外部代码可以方便地获取类中各个属性的值,
// 在需要访问联系人的具体属性信息时比如查看联系人的用户名、别名等这些getter方法能提供便捷的数据访问途径便于后续业务逻辑使用这些数据。
// - 自动生成所有私有属性对应的setter方法使得外部代码能够根据业务需求动态地修改对象的属性值例如当联系人的备注信息发生变化
// 可以通过调用setRemark(String newRemark)方法来更新remark属性的值从而保证对象的属性能够灵活地反映联系人相关信息的实际变化情况增强了属性的可操作性。
// - 生成toString方法该方法能将Contact对象以一种直观、易于阅读的字符串形式展示出来通常会包含类名以及各个属性的值
// 在调试程序时通过打印对象的toString结果可以快速查看当前联系人对象的具体状态了解各个属性的取值情况便于排查问题。
// - 生成hashCode方法在将对象存储到基于哈希的集合如HashMap、HashSet等中时会用到这个方法
// 它依据对象的属性值计算出一个唯一的哈希码,用于确定对象在哈希集合中的存储位置,方便在集合中快速查找和比较对象。
// - 生成equals方法用于比较两个Contact对象是否在逻辑上相等也就是判断它们的所有属性值是否都完全相同
// 在涉及联系人对象比较的业务逻辑中(如判断两个联系人的信息是否一致等情况),该方法能准确地进行对象的相等性判断。
// 通过使用@Data注解大大减少了手动编写这些常规方法的工作量让代码更加简洁、易读且易于维护。
@TableName(value = "Contact", autoResultMap = true)
// @TableName注解来自于MyBatis Plus框架用于指定该实体类对应的数据库表名这里表明Contact类对应的数据库表名为"Contact"。
// 而autoResultMap = true这个配置表示自动构建结果映射方便在查询数据库返回结果时能自动将结果集的数据映射到该类的属性上
// 减少了手动配置结果映射的繁琐过程,特别是当表结构和类结构有一定对应关系时,能更便捷地进行数据库与实体类之间的数据交互。
public class Contact {
/**
*
* String
// 在整个系统中,不同的联系人应该具有不同的用户名,通过这个用户名可以在数据库操作(如查询、更新、删除等)以及业务逻辑处理中准确地定位到具体的联系人,
// 同时在用户界面展示联系人列表等场景下,也是用户识别不同联系人的重要依据之一,并且作为主键,它在数据库表的关联、索引等操作中起着核心作用。
*/
@TableId(value = "UserName")
// @TableId注解用于指定该属性对应的数据库表中的主键字段名这里表明在数据库表"Contact"中,主键字段名为"UserName"
// 即将类中的userName属性与数据库表中的主键列进行了关联确保了在数据库操作时能根据这个主键进行准确的记录定位和操作保证数据的完整性和一致性。
private String userName;
/**
*
* String便
// 它可以与用户名、昵称等有所不同,在一些特定的业务场景下(如快捷查找、特定分组标识等),别名能够提供更方便的操作方式,用于辅助对联系人的管理和使用。
*/
@TableField("Alias")
// @TableField注解用于指定该属性对应的数据库表中的字段名这里表示在数据库表"Contact"中,该属性对应名为"Alias"的字段,
// 明确了类属性与数据库表字段之间的映射关系,确保数据的正确存储和读取,便于与数据库进行交互来获取和修改别名信息。
private String alias;
/**
*
* String
// 在涉及数据传输、存储或者一些需要增强安全性的业务场景中,对用户名进行加密可以防止用户名被恶意获取和利用,
// 并且在特定的验证、解密等相关业务逻辑中会使用到这个加密后的用户名信息。
*/
@TableField("EncryptUserName")
private String encryptUserName;
/**
* 0
* 0使Integer
// 一般来说0表示联系人未被删除而其他特定的值如1等具体取决于业务定义可以表示联系人已被删除
// 在进行数据清理、查询有效联系人列表或者恢复已删除联系人等业务操作时,会依据这个删除标志来进行相应的逻辑处理。
*/
@TableField("DelFlag")
private Integer delFlag;
/**
* 0
* 0
// 例如可以用不同的整数值来区分是好友、公众号、企业联系人等不同类型的联系人初始默认值为0在创建或初始化联系人信息时会用到这个默认值
// 后续可根据实际情况对其进行修改和判断,以实现不同类型联系人对应的业务逻辑处理。
*/
@TableField("Type")
private Integer type;
/**
* 0
* 0
// 比如在添加好友等场景中0可能表示未验证1表示已验证通过等情况在涉及联系人验证相关的业务逻辑如显示验证提示、限制未验证联系人的部分操作等中会用到这个标志进行判断和处理。
*/
@TableField("VerifyFlag")
private Integer verifyFlag;
/**
* 1
* 1Integer
// 目前可能暂时没有具体的使用场景,但当后续需要增加新的属性或者功能时,可以利用这些预留字段进行扩展,避免了频繁修改数据库表结构和实体类结构带来的复杂性和风险。
*/
@TableField("Reserved1")
private Integer reserved1;
/**
* 2
* 2Integer1
// 其具体用途会根据未来业务发展的需求来确定,在当前阶段不参与主要的业务逻辑处理,但为系统升级、功能拓展提前做好了准备。
*/
@TableField("Reserved2")
private Integer reserved2;
/**
* 3
* 3String
// 具体内容和用途将根据未来业务调整来确定,方便在不改动现有主要业务逻辑的基础上进行功能的扩展和完善。
*/
@TableField("Reserved3")
private String reserved3;
/**
* 4
* 4String
// 目前处于备用状态,等待合适的业务场景出现后再进行具体的使用。
*/
@TableField("Reserved4")
private String reserved4;
/**
*
* String
// 方便用户更好地识别和记忆联系人,例如可以备注联系人的工作单位、与自己的关系等信息,在查看联系人详情、进行联系人分类管理等场景中会展示和使用备注信息。
*/
@TableField("Remark")
private String remark;
/**
*
* String
// 在联系人列表展示、聊天界面等场景中,昵称更便于用户直观地识别联系人,增强了用户与联系人之间交互的友好性。
*/
@TableField("NickName")
private String nickName;
/**
* ID
* IDStringID
// 例如可以用不同的标签来区分工作联系人、生活联系人、兴趣爱好相同的联系人等标签ID列表可能是以某种特定格式如逗号分隔的ID字符串等存储多个标签的标识信息
// 在进行联系人筛选、分类查询等业务场景中会用到这些标签ID信息。
*/
@TableField("LabelIDList")
private String labelIdList;
/**
*
* String
// 比如在企业应用中可以表示不同的部门、项目组等划分,在社交应用中可能表示不同的社交圈子等,通过域列表可以更清晰地对联系人进行组织和管理,
// 在涉及联系人归属范围判断、跨域操作限制等业务逻辑中会使用到域列表信息。
*/
@TableField("DomainList")
private String domainList;
/**
*
* Integer
// 具体的聊天室类型划分取决于业务定义,例如可以区分普通群聊、临时群聊、特定主题群聊等不同类型,在群聊相关的业务处理(如群聊功能权限判断、群聊分类统计等)中会用到这个属性进行区分和操作。
*/
@TableField("ChatRoomType")
private Integer chatRoomType;
/**
*
* String
// 这个属性通常用于实现一些便捷的查找、排序功能,比如按照拼音首字母对联系人进行排序,或者通过输入拼音首字母快速定位联系人等,
// 方便用户在大量联系人中更高效地查找和操作特定的联系人。
*/
@TableField("PYInitial")
private String pyInitial;
/**
*
* String
// 完整拼音也可用于更精准的查找、排序以及一些基于拼音的匹配等业务操作,例如实现模糊拼音搜索联系人等功能,进一步提升联系人查找的便捷性。
*/
@TableField("QuanPin")
private String quanPin;
/**
*
* String
// 特别是当用户对备注内容有印象但记不清具体文字时,可以通过拼音首字母来快速定位对应的联系人,提高操作效率。
*/
@TableField("RemarkPYInitial")
private String remarkPyInitial;
/**
*
* String
// 可以基于完整拼音实现更细致的查找、匹配等功能,方便用户根据备注相关的拼音信息来操作联系人。
*/
@TableField("RemarkQuanPin")
private String remarkQuanPin;
/**
* URL
* URLString
// 通过这个链接可以获取对应的大头像图片并进行展示,让用户更清晰地查看联系人头像,提升用户体验和视觉效果。
*/
@TableField("BigHeadImgUrl")
private String bigHeadImgUrl;
/**
* URL
* URLString
// 小头像可能在一些列表展示等场景中使用,以节省空间同时又能让用户大致识别联系人,通过这个链接可以获取小头像图片进行展示,满足不同场景下的头像展示需求。
*/
@TableField("SmallHeadImgUrl")
private String smallHeadImgUrl;
/**
* MD5
* MD5StringMD5MD5
// 在这里主要用于验证头像文件的完整性、唯一性以及进行头像文件的比对等操作例如在头像更新时可以通过比较MD5值来判断头像是否真正发生了变化
// 或者在从不同来源获取头像时,验证其是否是同一个头像文件,确保头像数据的准确性和一致性。
*/
@TableField("HeadImgMd5")
private String headImgMd5;
/**
* 0
* 0Integer
// 0通常表示不接收通知而其他值如1等具体取决于业务定义可以表示接收通知在群聊消息提醒设置、根据用户偏好控制通知等业务逻辑中会用到这个标志进行判断和处理。
*/
@TableField("ChatRoomNotify")
private Integer chatRoomNotify;
/**
* 5
* 5Integer
// 等待未来根据实际情况进行功能拓展时再做具体使用,为系统的可扩展性提供了一定的灵活性。
*/
@TableField("Reserved5")
private Integer reserved5;
/**
* 6
* 6String
// 以备后续业务需求出现时能够灵活应对,确保系统可以在不大量改动现有结构的基础上进行功能的扩充。
*/
@TableField("Reserved6")
private String reserved6;
/**
* 7
* 7String
// 其具体内容和使用方式将根据后续业务发展来确定。
*/
@TableField("Reserved7")
private String reserved7;
/**
* 8
* 8Integer
// 但在系统后续升级、功能拓展时可能会被赋予相应的含义和使用方式,便于系统的持续发展和优化。
*/
@TableField("Reserved8")
private Integer reserved8;
/**
* 9
* 9Integer
// 提前设置这些预留字段可以减少因业务拓展带来的数据库和代码结构频繁变动的问题。
*/
@TableField("Reserved9")
private Integer reserved9;
/**
* 10
* 10String便
// 增强系统对未来业务需求变化的适应性。
*/
@TableField("Reserved10")
private String reserved10;
/**
* 11
* 11String
// 等待合适的业务场景出现后再进行具体的使用,有助于系统在长期发展中保持可扩展性。
*/
@TableField("Reserved11")
private String reserved11;
private String reserved11;}
/**
*
*/
@TableField(value = "ExtraBuf", typeHandler = ByteArrayTypeHandler.class)
private byte[] extraBuf;
}

@ -7,36 +7,66 @@ import lombok.Data;
import org.apache.ibatis.type.ByteArrayTypeHandler;
/**
*
*
* ContactHeadImg
* 便
*
* @author xcs
* @date 20231222 1059
* &#064;date 20231222 1059
**/
@Data
// @Data注解由Lombok库提供它会自动为这个类生成一系列实用的方法具体如下
// - 自动生成所有私有属性对应的getter方法像通过调用getUsrName()、getCreateTime()等方法,外部代码可以方便地获取类中各个属性的值,
// 在需要访问联系人头像相关的具体属性信息时比如查看用户名、获取头像创建时间等这些getter方法能提供便捷的数据访问途径便于后续业务逻辑使用这些数据。
// - 自动生成所有私有属性对应的setter方法使得外部代码能够根据业务需求动态地修改对象的属性值例如当联系人头像的MD5值发生变化
// 可以通过调用setHeadImgMd5(String newHeadImgMd5)方法来更新headImgMd5属性的值从而保证对象的属性能够灵活地反映联系人头像相关信息的实际变化情况增强了属性的可操作性。
// - 生成toString方法该方法能将ContactHeadImg对象以一种直观、易于阅读的字符串形式展示出来通常会包含类名以及各个属性的值
// 在调试程序时通过打印对象的toString结果可以快速查看当前联系人头像对象的具体状态了解各个属性的取值情况便于排查问题。
// - 生成hashCode方法在将对象存储到基于哈希的集合如HashMap、HashSet等中时会用到这个方法
// 它依据对象的属性值计算出一个唯一的哈希码,用于确定对象在哈希集合中的存储位置,方便在集合中快速查找和比较对象。
// - 生成equals方法用于比较两个ContactHeadImg对象是否在逻辑上相等也就是判断它们的所有属性值是否都完全相同
// 在涉及联系人头像对象比较的业务逻辑中(如判断两个联系人头像的相关属性是否一致等情况),该方法能准确地进行对象的相等性判断。
// 通过使用@Data注解大大减少了手动编写这些常规方法的工作量让代码更加简洁、易读且易于维护。
@TableName("ContactHeadImg1")
// @TableName注解来自MyBatis Plus框架用于指定该实体类对应的数据库表名这里表明ContactHeadImg类对应的数据库表名为"ContactHeadImg1"
// 明确了该类与数据库表之间的映射关系,方便后续进行数据库操作(如数据的插入、查询、更新、删除等)时能准确地找到对应的表,确保数据的正确交互。
public class ContactHeadImg {
/**
*
* String
// 在整个系统中,不同联系人的头像数据通过这个用户名进行区分,通过这个用户名可以在数据库操作(如查询、更新、删除等)以及业务逻辑处理中准确地定位到具体联系人的头像记录,
// 并且作为主键,它在数据库表的关联、索引等操作中起着核心作用,确保数据的完整性和一致性,方便对联系人头像数据进行精准的管理。
*/
@TableId("usrName")
// @TableId注解用于指定该属性对应的数据库表中的主键字段名这里表明在数据库表"ContactHeadImg1"中,主键字段名为"usrName"
// 即将类中的usrName属性与数据库表中的主键列进行了关联确保了在数据库操作时能根据这个主键进行准确的记录定位和操作。
private String usrName;
/**
*
* Integer
// 例如可能是以时间戳从某个固定起始时间点到头像创建时刻所经过的秒数或毫秒数常见以1970年1月1日00:00:00 UTC为起始点的形式存在
// 在头像管理中,创建时间可用于判断头像的新旧程度、进行头像历史记录查询以及按照时间顺序对头像数据进行排序等业务操作,方便对头像数据的生命周期进行管理。
*/
@TableField("createTime")
// @TableField注解用于指定该属性对应的数据库表中的字段名这里表示在数据库表"ContactHeadImg1"中,该属性对应名为"createTime"的字段,
// 明确了类属性与数据库表字段之间的映射关系,确保数据的正确存储和读取,便于与数据库进行交互来获取和修改创建时间信息。
private Integer createTime;
/**
*
* byte[]使ByteArrayTypeHandler
// 因为图像数据本身是二进制格式的,字节数组能够很好地承载这些二进制数据,方便在数据库中进行存储和读取,在需要展示联系人小头像的业务场景中(比如联系人列表中以较小尺寸展示头像),
// 可以通过读取这个字节数组数据还原出小头像图像进行展示,满足不同场景下对联系人头像展示的需求。
*/
@TableField(value = "smallHeadBuf", typeHandler = ByteArrayTypeHandler.class)
private byte[] smallHeadBuf;
/**
* MD5
* MD5StringMD5MD5
// 在这里主要用于验证头像数据的完整性、唯一性以及进行头像文件的比对等操作例如在头像更新时可以通过比较MD5值来判断头像是否真正发生了变化
// 或者在从不同来源获取头像时,验证其是否是同一个头像文件,确保头像数据的准确性和一致性,保障系统中联系人头像相关业务的正常运行。
*/
@TableField("m_headImgMD5")
private String headImgMd5;
}
}

@ -6,47 +6,77 @@ import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
*
*
* ContactHeadImgUrl
*
* 便
* @author xcs
* @date 20231221 1831
* &#064;date 20231221 1831
**/
@Data
// @Data注解由Lombok库提供它会自动为这个类生成一系列实用的方法具体如下
// - 自动生成所有私有属性对应的getter方法像通过调用getUsrName()、getSmallHeadImgUrl()等方法,外部代码可以方便地获取类中各个属性的值,
// 在需要访问联系人头像相关的具体属性信息时比如查看用户名、获取小头像或大头像的URL地址等这些getter方法能提供便捷的数据访问途径便于后续业务逻辑使用这些数据。
// - 自动生成所有私有属性对应的setter方法使得外部代码能够根据业务需求动态地修改对象的属性值例如当联系人的大头像图片的URL地址发生变化
// 可以通过调用setBigHeadImgUrl(String newBigHeadImgUrl)方法来更新bigHeadImgUrl属性的值从而保证对象的属性能够灵活地反映联系人头像相关信息的实际变化情况增强了属性的可操作性。
// - 生成toString方法该方法能将ContactHeadImgUrl对象以一种直观、易于阅读的字符串形式展示出来通常会包含类名以及各个属性的值
// 在调试程序时通过打印对象的toString结果可以快速查看当前联系人头像对象的具体状态了解各个属性的取值情况便于排查问题。
// - 生成hashCode方法在将对象存储到基于哈希的集合如HashMap、HashSet等中时会用到这个方法
// 它依据对象的属性值计算出一个唯一的哈希码,用于确定对象在哈希集合中的存储位置,方便在集合中快速查找和比较对象。
// - 生成equals方法用于比较两个ContactHeadImgUrl对象是否在逻辑上相等也就是判断它们的所有属性值是否都完全相同
// 在涉及联系人头像对象比较的业务逻辑中(如判断两个联系人的头像相关属性是否一致等情况),该方法能准确地进行对象的相等性判断。
// 通过使用@Data注解大大减少了手动编写这些常规方法的工作量让代码更加简洁、易读且易于维护。
@TableName("ContactHeadImgUrl")
// @TableName注解来自MyBatis Plus框架用于指定该实体类对应的数据库表名这里表明ContactHeadImgUrl类对应的数据库表名为"ContactHeadImgUrl"
// 明确了该类与数据库表之间的映射关系,方便后续进行数据库操作(如数据的插入、查询、更新、删除等)时能准确地找到对应的表,确保数据的正确交互。
public class ContactHeadImgUrl {
/**
*
* String
// 在整个系统中,不同联系人的头像信息通过这个用户名进行区分,通过这个用户名可以在数据库操作(如查询、更新、删除等)以及业务逻辑处理中准确地定位到具体联系人的头像记录,
// 并且在展示联系人头像、进行头像相关数据管理等场景下,也是重要的关联依据,确保头像数据与对应的联系人能准确匹配。
*/
@TableId("usrName")
// @TableId注解用于指定该属性对应的数据库表中的主键字段名这里表明在数据库表"ContactHeadImgUrl"中,主键字段名为"usrName"
// 即将类中的usrName属性与数据库表中的主键列进行了关联确保了在数据库操作时能根据这个主键进行准确的记录定位和操作保证数据的完整性和一致性。
private String usrName;
/**
* URL
* URLString
// 通过这个URL地址系统可以从相应的服务器或者存储位置获取小头像图片并进行展示满足不同展示场景对头像尺寸和展示效果的需求方便用户快速识别联系人。
*/
@TableField("smallHeadImgUrl")
// @TableField注解用于指定该属性对应的数据库表中的字段名这里表示在数据库表"ContactHeadImgUrl"中,该属性对应名为"smallHeadImgUrl"的字段,
// 明确了类属性与数据库表字段之间的映射关系确保数据的正确存储和读取便于与数据库进行交互来获取和修改小头像图片的URL地址信息。
private String smallHeadImgUrl;
/**
* URL
* URL
// 通过这个URL地址系统可以获取大头像图片进行展示能让用户更清晰地查看联系人头像细节提升用户体验同时也方便根据不同的业务需求灵活切换头像展示的尺寸。
*/
@TableField("bigHeadImgUrl")
private String bigHeadImgUrl;
/**
* MD5
* MD5StringMD5MD5
// 在这里主要用于验证头像图片的完整性、唯一性以及进行头像文件的比对等操作例如在头像更新时可以通过比较MD5值来判断头像是否真正发生了变化
// 或者在从不同来源获取头像时,验证其是否是同一个头像文件,确保头像数据的准确性和一致性,保障系统中联系人头像相关业务的正常运行。
*/
@TableField("headImgMd5")
private String headImgMd5;
/**
* 0
* 0Integer
// 目前可能暂时没有具体的使用场景,但当后续需要增加新的属性或者功能时,可以利用这些预留字段进行扩展,避免了频繁修改数据库表结构和实体类结构带来的复杂性和风险。
*/
@TableField("reverse0")
private Integer reverse0;
/**
* 1
* 1String0
// 其具体内容和用途会根据未来业务发展的需求来确定,在当前阶段不参与主要的业务逻辑处理,但为系统升级、功能拓展提前做好了准备。
*/
@TableField("reverse1")
private String reverse1;

@ -7,60 +7,70 @@ import lombok.Data;
/**
*
* MyBatis Plus
* Lombok @Data GetterSetterToString
*
* @author xcs
* @date 20231222 1653
* &#064;date 20231222 1653
**/
@Data
@TableName("ContactLabel")
@TableName("ContactLabel") // 表明该实体类对应的数据库表名为 "ContactLabel"用于MyBatis Plus与数据库表进行关联映射
public class ContactLabel {
/**
* Id
* @TableId "LabelId"
*/
@TableId("LabelId")
private String labelId;
/**
*
* 使 @TableField "LabelName"
*/
@TableField("LabelName")
private String labelName;
/**
* 1
* "Reserved1" Integer
*/
@TableField("Reserved1")
private Integer reserved1;
/**
* 2
* "Reserved2" Integer
*/
@TableField("Reserved2")
private Integer reserved2;
/**
* 3
* "Reserved3" String使
*/
@TableField("Reserved3")
private String reserved3;
/**
* 4
* "Reserved4" 便String
*/
@TableField("Reserved4")
private String reserved4;
/**
* 5
* "Reserved5" String使
*/
@TableField("Reserved5")
private String reserved5;
/**
*
* "RespData"
*/
@TableField("RespData")
private String respData;
}
}

@ -8,35 +8,43 @@ import lombok.Data;
/**
* FTSContactContent
* MyBatis Plus
* Lombok @Data GetterSetterToString
*
* @author xcs
* @date 202461415:12:27
* &#064;date 202461415:12:27
**/
@Data
@TableName(value = "FTSContact15_content", autoResultMap = true)
// @TableName注解用于指定该实体类对应的数据库表名是 "FTSContact15_content"autoResultMap = true表示自动映射结果集方便查询结果的映射处理
public class FTSContactContent {
/**
*
* "docid" @TableId IdType.AUTO
* 便
*/
@TableId(value = "docid", type = IdType.AUTO)
private Integer docId;
/**
* alias
* 使 @TableField "c0alias"
*/
@TableField("c0alias")
private String alias;
/**
* nickname
* @TableField "c1nickname"
*/
@TableField("c1nickname")
private String nickname;
/**
* c2remark
* "c2remark" 便
*/
@TableField("c2remark")
private String remark;
}
}

@ -6,30 +6,58 @@ import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* 使
*
* FTSRecentUsed使使
*
* 便
* @author xcs
* @date 20240123 1109
* &#064;date 20240123 1109
**/
@Data
// @Data注解由Lombok库提供它会自动为这个类生成一系列实用的方法具体如下
// - 自动生成所有私有属性对应的getter方法像通过调用getQueryText()、getUsername()等方法,外部代码可以方便地获取类中各个属性的值,
// 在需要访问最近使用关键字相关的具体属性信息时比如查看查询的内容、获取用户名等这些getter方法能提供便捷的数据访问途径便于后续业务逻辑使用这些数据。
// - 自动生成所有私有属性对应的setter方法使得外部代码能够根据业务需求动态地修改对象的属性值例如当查询的内容发生变化
// 可以通过调用setQueryText(String newQueryText)方法来更新queryText属性的值从而保证对象的属性能够灵活地反映最近使用关键字相关信息的实际变化情况增强了属性的可操作性。
// - 生成toString方法该方法能将FTSRecentUsed对象以一种直观、易于阅读的字符串形式展示出来通常会包含类名以及各个属性的值
// 在调试程序时通过打印对象的toString结果可以快速查看当前最近使用关键字对象的具体状态了解各个属性的取值情况便于排查问题。
// - 生成hashCode方法在将对象存储到基于哈希的集合如HashMap、HashSet等中时会用到这个方法
// 它依据对象的属性值计算出一个唯一的哈希码,用于确定对象在哈希集合中的存储位置,方便在集合中快速查找和比较对象。
// - 生成equals方法用于比较两个FTSRecentUsed对象是否在逻辑上相等也就是判断它们的所有属性值是否都完全相同
// 在涉及最近使用关键字对象比较的业务逻辑中(如判断两个用户的搜索历史记录是否一致等情况),该方法能准确地进行对象的相等性判断。
// 通过使用@Data注解大大减少了手动编写这些常规方法的工作量让代码更加简洁、易读且易于维护。
@TableName("FTSRecentUsed15")
// @TableName注解来自MyBatis Plus框架用于指定该实体类对应的数据库表名这里表明FTSRecentUsed类对应的数据库表名为"FTSRecentUsed15"
// 明确了该类与数据库表之间的映射关系,方便后续进行数据库操作(如数据的插入、查询、更新、删除等)时能准确地找到对应的表,确保数据的正确交互。
public class FTSRecentUsed {
/**
*
* String
// 这是体现用户搜索意图的关键信息,通过记录这些查询内容,可以分析用户的兴趣点、常用搜索需求等,
// 在搜索历史展示、基于历史搜索进行智能提示或者个性化推荐等业务场景中,查询的内容属性起着重要作用,便于为用户提供更贴合需求的服务。
*/
@TableId("queryText")
// @TableId注解用于指定该属性对应的数据库表中的主键字段名这里表明在数据库表"FTSRecentUsed15"中,主键字段名为"queryText"
// 即将类中的queryText属性与数据库表中的主键列进行了关联确保了在数据库操作时能根据这个主键进行准确的记录定位和操作保证数据的完整性和一致性。
private String queryText;
/**
*
* Integer
// 通过这个用户名可以区分不同用户的搜索历史记录,明确各条最近使用关键字是属于哪个具体用户的,方便在多用户环境下进行数据的准确管理和个性化服务的提供,
// 例如为不同用户分别展示其对应的搜索历史,或者基于不同用户的搜索习惯进行针对性的推荐等操作。
*/
@TableField("username")
// @TableField注解用于指定该属性对应的数据库表中的字段名这里表示在数据库表"FTSRecentUsed15"中,该属性对应名为"username"的字段,
// 明确了类属性与数据库表字段之间的映射关系,确保数据的正确存储和读取,便于与数据库进行交互来获取和修改用户名信息。
private Integer username;
/**
*
* String使
// 时间的存储格式可能是常见的日期时间格式(如"yyyy-MM-dd HH:mm:ss"等),通过这个修改时间,可以了解用户使用关键字的时间顺序、判断关键字的时效性,
// 在搜索历史排序展示(按照时间先后顺序展示近期使用的关键字)、清理过期的搜索记录等业务操作中会用到这个属性,方便对搜索历史数据进行有效的管理。
*/
@TableField("updateTime")
private String updateTime;
}
}

@ -6,72 +6,105 @@ import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
*
*
* Feeds
* 便
* @author xcs
* @date 20240103 1641
* &#064;date 20240103 1641
**/
@Data
// @Data注解由Lombok库提供它会自动为这个类生成一系列实用的方法具体如下
// - 自动生成所有私有属性对应的getter方法例如通过调用getFeedId()、getCreateTime()等方法,外部代码可以方便地获取类中各个属性的值,
// 在需要访问朋友圈动态的具体属性信息时比如查看动态的唯一标识ID、获取创建时间等这些getter方法能提供便捷的数据访问途径便于后续业务逻辑使用这些数据。
// - 自动生成所有私有属性对应的setter方法使得外部代码能够根据业务需求动态地修改对象的属性值例如当朋友圈动态的内容文本发生变化
// 可以通过调用setContent(String newContent)方法来更新content属性的值从而保证对象的属性能够灵活地反映朋友圈动态相关信息的实际变化情况增强了属性的可操作性。
// - 生成toString方法该方法能将Feeds对象以一种直观、易于阅读的字符串形式展示出来通常会包含类名以及各个属性的值
// 在调试程序时通过打印对象的toString结果可以快速查看当前朋友圈动态对象的具体状态了解各个属性的取值情况便于排查问题。
// - 生成hashCode方法在将对象存储到基于哈希的集合如HashMap、HashSet等中时会用到这个方法
// 它依据对象的属性值计算出一个唯一的哈希码,用于确定对象在哈希集合中的存储位置,方便在集合中快速查找和比较对象。
// - 生成equals方法用于比较两个Feeds对象是否在逻辑上相等也就是判断它们的所有属性值是否都完全相同
// 在涉及朋友圈动态对象比较的业务逻辑中(如判断两条朋友圈动态的信息是否一致等情况),该方法能准确地进行对象的相等性判断。
// 通过使用@Data注解大大减少了手动编写这些常规方法的工作量让代码更加简洁、易读且易于维护。
@TableName(value = "FeedsV20", autoResultMap = true)
// @TableName注解来自于MyBatis Plus框架用于指定该实体类对应的数据库表名这里表明Feeds类对应的数据库表名为"FeedsV20"。
// 而autoResultMap = true这个配置表示自动构建结果映射方便在查询数据库返回结果时能自动将结果集的数据映射到该类的属性上
// 减少了手动配置结果映射的繁琐过程,特别是当表结构和类结构有一定对应关系时,能更便捷地进行数据库与实体类之间的数据交互。
public class Feeds {
/**
* ID
* IDLong
// 不同的朋友圈动态应该具有不同的ID通过这个ID可以在数据库操作如查询、更新、删除等以及业务逻辑处理中准确地定位到具体的动态记录
// 同时在朋友圈的各种业务场景中,比如查看特定动态详情、进行动态的排序展示等,也是重要的依据,方便对朋友圈动态进行精准的管理和操作。
*/
@TableId("FeedId")
// @TableId注解用于指定该属性对应的数据库表中的主键字段名这里表明在数据库表"FeedsV20"中,主键字段名为"FeedId"
// 即将类中的feedId属性与数据库表中的主键列进行了关联确保了在数据库操作时能根据这个主键进行准确的记录定位和操作保证数据的完整性和一致性。
private Long feedId;
/**
*
* 使Integer19701100:00:00 UTC
// 也可能是经过特定格式转换后的整数值,在朋友圈动态管理中,创建时间可用于按照时间顺序对动态进行排序展示(如按发布时间先后展示朋友圈)、进行动态历史记录查询以及判断动态的时效性等业务操作,方便对朋友圈动态的生命周期进行管理。
*/
@TableField("CreateTime")
// @TableField注解用于指定该属性对应的数据库表中的字段名这里表示在数据库表"FeedsV20"中,该属性对应名为"CreateTime"的字段,
// 明确了类属性与数据库表字段之间的映射关系,确保数据的正确存储和读取,便于与数据库进行交互来获取和修改创建时间信息。
private Integer createTime;
/**
* ID
* IDIntegerID
// 例如当动态发布失败、展示出现问题等故障发生时可以通过这个故障ID去查找具体的故障原因、相关的报错日志等详细信息便于进行故障排查和系统维护保障朋友圈功能的正常运行。
*/
@TableField("FaultId")
private Integer faultId;
/**
*
* Integer
// 比如可以用不同的整数值来表示是纯文本动态、图文动态、视频动态等不同类型,在朋友圈动态的展示、处理逻辑中,会根据这个类型属性来采取不同的展示方式、业务操作,以满足多样化的朋友圈功能需求。
*/
@TableField("Type")
private Integer type;
/**
*
* String
// 在朋友圈的展示、权限管理等业务场景中起着重要作用,比如只展示当前用户及其好友的朋友圈动态,就需要通过这个用户名来判断动态的发布者与当前用户的关系,从而决定是否展示该动态。
*/
@TableField("UserName")
private String userName;
/**
*
* Integer
// 例如可以用不同的整数值来区分动态是正常发布状态、已删除状态、审核中状态(如果有审核机制的话)等不同情况,在朋友圈动态的管理、操作判断等业务逻辑中会依据这个状态属性来进行相应的处理。
*/
@TableField("Status")
private Integer status;
/**
*
* Integer
// 例如可以通过不同的位来表示是否开启了某些扩展功能(如动态是否可评论、是否可转发等扩展功能的标志位),方便在业务逻辑中根据这些标志来实现更丰富、灵活的朋友圈功能。
*/
@TableField("ExtFlag")
private Integer extFlag;
/**
*
* Integer
// 比如0表示公开所有人都能看到1表示仅好友可见2表示仅自己可见等等在朋友圈动态的展示权限控制方面起着关键作用根据用户设置的隐私标志来决定哪些用户能够查看对应的动态内容。
*/
@TableField("PrivFlag")
private Integer privFlag;
/**
* ID
* IDString
// 通过这个字符串ID去匹配其他表中的对应记录实现更复杂的数据关联和业务逻辑处理例如关联到动态的评论表、点赞表等相关数据方便对朋友圈动态的附属信息进行统一管理和操作。
*/
@TableField("StringId")
private String stringId;
/**
*
* String
// 如果是图文、视频等类型的动态,这里可能存储的是对内容的简要描述等文本信息,在朋友圈动态的展示环节,这个属性的值就是用户实际看到的动态文字内容,是朋友圈动态的核心展示部分之一。
*/
@TableField("Content")
private String content;
}
}

@ -8,48 +8,57 @@ import org.apache.ibatis.type.ByteArrayTypeHandler;
/**
*
* MyBatis Plus
* Lombok @Data GetterSetter便
*
* @author xcs
* @date 20240104 1755
* &#064;date 20240104 1755
**/
@Data
@TableName(value = "HardLinkImageAttribute", autoResultMap = true)
// @TableName注解用于指定该实体类对应的数据库表名为 "HardLinkImageAttribute"autoResultMap = true表示自动映射结果集便于在查询等操作后将数据库结果准确映射到该实体对象上
public class HardLinkImageAttribute {
/**
* ID
* @TableId "Md5Hash" 使LongMD5
*/
@TableId("Md5Hash")
private Long md5Hash;
/**
*
* 使 @TableField "DirID1" 便
*/
@TableField("DirID1")
private String dirId1;
/**
*
* @TableField "DirID2"
*/
@TableField("DirID2")
private String dirId2;
/**
*
* "Md5" 使 ByteArrayTypeHandler MD5
*/
@TableField(value = "Md5", typeHandler = ByteArrayTypeHandler.class)
private byte[] md5;
/**
*
* @TableField "ModifyTime" 便
*/
@TableField("ModifyTime")
private String modifyTime;
/**
*
* @TableField "FileName" 便
*/
@TableField("FileName")
private String fileName;
}
}

@ -7,49 +7,84 @@ import lombok.Data;
import org.apache.ibatis.type.ByteArrayTypeHandler;
/**
*
*
* HardLinkVideoAttribute
* 便
*
* @author xcs
* @date 20240207 1524
* &#064;date 20240207 1524
**/
@Data
// @Data注解由Lombok库提供它会自动为这个类生成一系列实用的方法具体如下
// - 自动生成所有私有属性对应的getter方法例如通过调用getMd5Hash()、getDirId1()等方法,外部代码可以方便地获取类中各个属性的值,
// 在需要访问视频链接相关的具体属性信息时比如查看动态的唯一标识ID、获取发布用户的用户名等这些getter方法能提供便捷的数据访问途径便于后续业务逻辑使用这些数据。
// - 自动生成所有私有属性对应的setter方法使得外部代码能够根据业务需求动态地修改对象的属性值例如当视频的文件名发生变化
// 可以通过调用setFileName(String newFileName)方法来更新fileName属性的值从而保证对象的属性能够灵活地反映视频链接相关信息的实际变化情况增强了属性的可操作性。
// - 生成toString方法该方法能将HardLinkVideoAttribute对象以一种直观、易于阅读的字符串形式展示出来通常会包含类名以及各个属性的值
// 在调试程序时通过打印对象的toString结果可以快速查看当前视频链接对象的具体状态了解各个属性的取值情况便于排查问题。
// - 生成hashCode方法在将对象存储到基于哈希的集合如HashMap、HashSet等中时会用到这个方法
// 它依据对象的属性值计算出一个唯一的哈希码,用于确定对象在哈希集合中的存储位置,方便在集合中快速查找和比较对象。
// - 生成equals方法用于比较两个HardLinkVideoAttribute对象是否在逻辑上相等也就是判断它们的所有属性值是否都完全相同
// 在涉及视频链接对象比较的业务逻辑中(如判断两条视频链接的相关属性是否一致等情况),该方法能准确地进行对象的相等性判断。
// 通过使用@Data注解大大减少了手动编写这些常规方法的工作量让代码更加简洁、易读且易于维护。
@TableName(value = "HardLinkVideoAttribute", autoResultMap = true)
// @TableName注解来自于MyBatis Plus框架用于指定该实体类对应的数据库表名这里表明HardLinkVideoAttribute类对应的数据库表名为"HardLinkVideoAttribute"。
// 而autoResultMap = true这个配置表示自动构建结果映射方便在查询数据库返回结果时能自动将结果集的数据映射到该类的属性上
// 减少了手动配置结果映射的繁琐过程,特别是当表结构和类结构有一定对应关系时,能更便捷地进行数据库与实体类之间的数据交互。
public class HardLinkVideoAttribute {
/**
* ID
* IDLong
// 不同的视频链接记录应该具有不同的ID通过这个ID可以在数据库操作如查询、更新、删除等以及业务逻辑处理中准确地定位到具体的记录
// 同时在视频链接相关的各种业务场景中,比如查看特定视频链接详情、进行视频链接的排序展示等,也是重要的依据,方便对视频链接进行精准的管理和操作,
// 这里使用MD5哈希值假设MD5Hash代表的是基于视频相关特征生成的MD5哈希值作为唯一标识有助于保证数据的唯一性和准确性。
*/
@TableId("Md5Hash")
// @TableId注解用于指定该属性对应的数据库表中的主键字段名这里表明在数据库表"HardLinkVideoAttribute"中,主键字段名为"Md5Hash"
// 即将类中的md5Hash属性与数据库表中的主键列进行了关联确保了在数据库操作时能根据这个主键进行准确的记录定位和操作保证数据的完整性和一致性。
private Long md5Hash;
/**
*
* String
// 在视频链接的权限管理、归属判断以及相关业务场景中起着重要作用,比如判断当前用户是否有权限查看、操作该视频链接,或者统计不同用户发布视频链接的情况等,都需要依据这个用户名来进行相应的处理。
*/
@TableField("DirID1")
// @TableField注解用于指定该属性对应的数据库表中的字段名这里表示在数据库表"HardLinkVideoAttribute"中,该属性对应名为"DirID1"的字段,
// 明确了类属性与数据库表字段之间的映射关系,确保数据的正确存储和读取,便于与数据库进行交互来获取和修改用户名信息。不过此处字段名"DirID1"看起来不太直观表示用户名,
// 可能在具体业务中有其特定含义或映射关系,需结合实际业务场景进一步理解。
private String dirId1;
/**
*
* 使
// 例如可能从不同维度来关联用户与视频链接的关系,具体含义需要参照具体的业务规则和数据库设计来确定,但总体来说都是用于明确视频链接发布者身份的重要属性。
*/
@TableField("DirID2")
private String dirId2;
/**
*
* byte[]使ByteArrayTypeHandler
// 有可能它存储的是基于视频相关内容比如视频文件本身计算出的MD5值如果按照合理推测可能和前面提到的MD5Hash有一定关联但又不同的用途用于数据验证、唯一性判断或者与其他系统交互时识别视频的关键标识等
// 具体作用还是要结合整个系统关于视频链接处理的业务逻辑来准确理解。
*/
@TableField(value = "Md5", typeHandler = ByteArrayTypeHandler.class)
private byte[] md5;
/**
*
* String"yyyy-MM-dd HH:mm:ss"
// 在视频链接的管理中,通过这个修改时间可以了解视频链接相关数据的更新情况,比如判断是否有新的变动、进行历史记录查询以及按照时间顺序对视频链接进行排序展示等业务操作,方便对视频链接的生命周期进行管理,
// 不过这里同样字段名"ModifyTime"更直观表示修改时间,和注释里“发布用户的用户名”不太相符,应按照实际业务场景准确理解其含义。
*/
@TableField("ModifyTime")
private String modifyTime;
/**
*
* String便
// 同时在文件存储、检索以及与其他系统进行文件相关交互等业务场景中,文件名也起着关键作用,有助于准确地定位和操作具体的视频文件对应的链接信息。
*/
@TableField("FileName")
private String fileName;
}
}

@ -1,6 +1,5 @@
package com.xcs.wx.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
@ -10,167 +9,219 @@ import org.apache.ibatis.type.ByteArrayTypeHandler;
/**
*
* MyBatis Plus
* Lombok @Data GetterSetter便
*
* @author xcs
* @date 20231225 1508
* &#064;date 20231225 1508
**/
@Data
@TableName(value = "MSG", autoResultMap = true)
// @TableName注解用于指定该实体类对应的数据库表名为 "MSG"autoResultMap = true表示自动映射结果集确保在进行数据库查询等操作后能准确地将结果映射到该实体对象的各个属性上
public class Msg {
/**
*
* @TableId "localId" IntegerIdType.AUTO
* 便
*/
@TableId(value = "localId",type = IdType.AUTO)
@TableId(value = "localId", type = IdType.AUTO)
private Integer localId;
/**
* ID
* 使 @TableField "TalkerId" ID
*
*/
@TableField("TalkerId")
private Integer talkerId;
/**
* ID
* @TableField "MsgSvrID" ID
*
*/
@TableField("MsgSvrID")
private String msgSvrId;
/**
*
* @TableField "Type"
*
*/
@TableField("Type")
private Integer type;
/**
*
* @TableField "SubType"
* 便
*/
@TableField("SubType")
private Integer subType;
/**
*
* 使 @TableField "IsSender" 10
*
*/
@TableField("IsSender")
private Integer isSender;
/**
*
* @TableField "CreateTime" 便
*
*/
@TableField("CreateTime")
private Integer createTime;
/**
* 0
* @TableField "Sequence" 0
* 使
*/
@TableField("Sequence")
private Long sequence;
/**
* 0
* @TableField "StatusEx" 0
*
*/
@TableField("StatusEx")
private Integer statusEx;
/**
*
* 使 @TableField "FlagEx"
*
*/
@TableField("FlagEx")
private Integer flagEx;
/**
*
* @TableField "Status" 便
*
*/
@TableField("Status")
private Integer status;
/**
*
* @TableField "MsgServerSeq" 使
*
*/
@TableField("MsgServerSeq")
private Integer msgServerSeq;
/**
*
* @TableField "MsgSequence"
* 使
*/
@TableField("MsgSequence")
private Integer msgSequence;
/**
*
* 使 @TableField "StrTalker"
* 便
*/
@TableField("StrTalker")
private String strTalker;
/**
*
* @TableField "StrContent"
*
*/
@TableField("StrContent")
private String strContent;
/**
*
* @TableField "DisplayContent"
*
*/
@TableField("DisplayContent")
private String displayContent;
/**
* 0 0
* 使 @TableField "Reserved0" 0
* 便
*/
@TableField("Reserved0")
private Integer reserved0;
/**
* 1 0
* @TableField "Reserved1" 0 Reserved0 使
*/
@TableField("Reserved1")
private Integer reserved1;
/**
* 2 0
* @TableField "Reserved2" 0
*/
@TableField("Reserved2")
private Integer reserved2;
/**
* 3 0
* @TableField "Reserved3" 0
*/
@TableField("Reserved3")
private Integer reserved3;
/**
* 4
* 使 @TableField "Reserved4"
* 使
*/
@TableField("Reserved4")
private String reserved4;
/**
* 5
* @TableField "Reserved5" Reserved4
* 便
*/
@TableField("Reserved5")
private String reserved5;
/**
* 6
* @TableField "Reserved6"
*
*/
@TableField("Reserved6")
private String reserved6;
/**
*
* "CompressContent" 使 ByteArrayTypeHandler
* 便
*/
@TableField(value = "CompressContent", typeHandler = ByteArrayTypeHandler.class)
private byte[] compressContent;
/**
*
* @TableField "BytesExtra" 使 ByteArrayTypeHandler
*
*/
@TableField(value = "BytesExtra", typeHandler = ByteArrayTypeHandler.class)
private byte[] bytesExtra;
/**
*
* 使 @TableField "BytesTrans" ByteArrayTypeHandler
*
*/
@TableField(value = "BytesTrans", typeHandler = ByteArrayTypeHandler.class)
private byte[] bytesTrans;
}
}

@ -6,90 +6,132 @@ import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
*
*
* Session
* 便
* @author xcs
* @date 20231221 1705
* &#064;date 20231221 1705
**/
@Data
// @Data注解由Lombok库提供它会自动为这个类生成一系列实用的方法具体如下
// - 自动生成所有私有属性对应的getter方法例如通过调用getUsrName()、getUnReadCount()等方法,外部代码可以方便地获取类中各个属性的值,
// 在需要访问会话的具体属性信息时比如查看用户名、获取未读消息计数等这些getter方法能提供便捷的数据访问途径便于后续业务逻辑使用这些数据。
// - 自动生成所有私有属性对应的setter方法使得外部代码能够根据业务需求动态地修改对象的属性值例如当会话的内容发生变化
// 可以通过调用setContent(String newContent)方法来更新content属性的值从而保证对象的属性能够灵活地反映会话相关信息的实际变化情况增强了属性的可操作性。
// - 生成toString方法该方法能将Session对象以一种直观、易于阅读的字符串形式展示出来通常会包含类名以及各个属性的值
// 在调试程序时通过打印对象的toString结果可以快速查看当前会话对象的具体状态了解各个属性的取值情况便于排查问题。
// - 生成hashCode方法在将对象存储到基于哈希的集合如HashMap、HashSet等中时会用到这个方法
// 它依据对象的属性值计算出一个唯一的哈希码,用于确定对象在哈希集合中的存储位置,方便在集合中快速查找和比较对象。
// - 生成equals方法用于比较两个Session对象是否在逻辑上相等也就是判断它们的所有属性值是否都完全相同
// 在涉及会话对象比较的业务逻辑中(如判断两个会话的信息是否一致等情况),该方法能准确地进行对象的相等性判断。
// 通过使用@Data注解大大减少了手动编写这些常规方法的工作量让代码更加简洁、易读且易于维护。
@TableName("Session")
// @TableName注解来自MyBatis Plus框架用于指定该实体类对应的数据库表名这里表明Session类对应的数据库表名为"Session"
// 明确了该类与数据库表之间的映射关系,方便后续进行数据库操作(如数据的插入、查询、更新、删除等)时能准确地找到对应的表,确保数据的正确交互。
public class Session {
/**
*
* String
// 在整个系统中,不同用户的会话记录通过这个用户名进行区分,通过这个用户名可以在数据库操作(如查询、更新、删除等)以及业务逻辑处理中准确地定位到具体用户的会话相关记录,
// 并且在展示会话列表、判断会话归属等场景下,也是重要的依据,确保会话数据与对应的用户能准确匹配。
*/
@TableId("strUsrName")
// @TableId注解用于指定该属性对应的数据库表中的主键字段名这里表明在数据库表"Session"中,主键字段名为"strUsrName"
// 即将类中的usrName属性与数据库表中的主键列进行了关联确保了在数据库操作时能根据这个主键进行准确的记录定位和操作保证数据的完整性和一致性。
private String usrName;
/**
*
* Integer
// 在会话列表展示等场景中,这个计数可以直观地提示用户有多少新消息等待查看,方便用户及时了解是否有未处理的消息,
// 同时在消息提醒、未读消息管理等业务逻辑中起着重要作用,例如可以根据未读消息数量决定是否进行特殊的提醒标识等操作。
*/
@TableField("nUnReadCount")
// @TableField注解用于指定该属性对应的数据库表中的字段名这里表示在数据库表"Session"中,该属性对应名为"nUnReadCount"的字段,
// 明确了类属性与数据库表字段之间的映射关系,确保数据的正确存储和读取,便于与数据库进行交互来获取和修改未读消息计数信息。
private Integer unReadCount;
/**
*
* String
// 它可能用于关联到会话所属的某个更高层级的实体(比如会话所在的分组、聊天窗口等),或者指向与该会话有特定关联关系的其他对象,
// 在涉及会话的组织架构、关联关系梳理以及复杂业务逻辑处理中会用到这个属性来建立不同实体之间的联系。
*/
@TableField("parentRef")
private String parentRef;
/**
*
* String
// 在会话展示等场景中,昵称更便于用户直观地识别会话对象,增强了用户与用户之间交互的友好性,相较于用户名,昵称更具亲和力,方便用户快速知晓对方身份。
*/
@TableField("strNickName")
private String nickName;
/**
*
* Integer
// 例如可以用不同的整数值来区分会话是正常开启状态、已关闭状态、冻结状态等不同情况,在会话的管理、操作判断等业务逻辑中会依据这个状态属性来进行相应的处理,
// 比如根据会话状态决定是否允许发送消息等操作。
*/
@TableField("nStatus")
private Integer status;
/**
*
* Integer
// 在消息发送的相关业务逻辑中,通过这个标识可以判断消息是否准确传达,便于进行后续的处理,比如重新发送失败的消息等操作。
*/
@TableField("nIsSend")
private Integer isSend;
/**
*
* String
// 无论是文本消息、表情等都可以以相应的文本形式存储在这里(如果涉及复杂的多媒体消息等可能会有其他关联处理方式),在展示会话历史记录、查看具体消息详情等场景中会用到这个属性来呈现消息内容。
*/
@TableField("strContent")
private String content;
/**
*
* Integer
// 例如可以用不同的整数值来区分是文本消息、图片消息、语音消息、视频消息等不同类型的消息,在消息的展示、处理逻辑中,会根据这个类型属性来采取不同的展示方式、业务操作,
// 以满足多样化的消息交互需求,比如对于图片消息要进行图片加载展示,对于语音消息要提供播放功能等。
*/
@TableField("nMsgType")
private Integer msgType;
/**
* ID
* IDInteger
// 通过这个ID可以在本地数据库或者相关存储中准确地定位到具体的消息记录方便进行消息的查询、更新、删除等操作
// 同时在消息的关联、排序以及与其他系统交互涉及消息标识等业务场景中起着重要作用,确保消息管理的准确性和便捷性。
*/
@TableField("nMsgLocalID")
private Integer msgLocalId;
/**
*
* Integer
// 类似消息的发送状态,但可能涵盖更广泛的情况,比如消息是否已读、是否被撤回、是否审核通过(如果有审核机制的话)等不同状态,
// 在消息管理、消息提醒以及相关业务逻辑中会依据这个状态属性来进行相应的处理,例如根据消息是否已读来决定是否取消未读提醒等操作。
*/
@TableField("nMsgStatus")
private Integer msgStatus;
/**
*
* Integer19701100:00:00 UTC
// 到消息实际发送或接收时刻所经过的秒数或者毫秒数(具体取决于系统的时间精度设定),通过这个时间戳,可以准确判断消息的先后顺序、进行消息的排序展示(按照时间顺序),
// 以及在一些基于时间范围的查询(如查看某一时间段内的消息记录)等业务场景中发挥作用,方便对会话中的消息进行时间维度的管理。
*/
@TableField("nTime")
private Integer time;
/**
*
* String
// 当用户对已发送的消息进行修改后,修改后的内容就会存储在这里,方便在查看消息历史记录时能够体现消息的变化情况,同时也便于进行相关的业务逻辑处理,比如记录消息编辑的日志等操作。
*/
@TableField("editContent")
private String editContent;
/**
* @
* @Integer@
// 例如值为1表示有其他人@我值为0表示没有在消息提醒、重点消息关注等业务逻辑中会用到这个标识方便用户快速定位到与自己相关的重要消息内容。
*/
@TableField("othersAtMe")
private Integer othersAtMe;
}
}

@ -6,36 +6,47 @@ import lombok.Data;
/**
* SQLite
* SQLite "sqlite_master" MyBatis Plus
* Lombok @Data GetterSetter便访
*
* @author xcs
* @date 202461309:18:29
* &#064;date 202461309:18:29
*/
@Data
@TableName("sqlite_master")
// @TableName注解用于指定该实体类对应的数据库表名为 "sqlite_master"表明这个类是与SQLite数据库中的该系统表相关联的实体映射类
public class SqliteMaster {
/**
* type
* 使 @TableField "type" "sqlite_master" "type"
* 'table''index''view'
*/
@TableField("type")
private String type;
/**
* tblName
* @TableField "tbl_name"
* "sqlite_master" 便
*/
@TableField("tbl_name")
private String tblName;
/**
* rootPage
* @TableField "rootpage" SQLite"rootpage"
*
*/
@TableField("rootpage")
private String rootPage;
/**
* sql
* 使 @TableField "sql" "sqlite_master" "sql" SQL
* 使CREATE TABLE
*/
@TableField("sql")
private String sql;
}
}

@ -4,22 +4,42 @@ import lombok.AllArgsConstructor;
import lombok.Data;
/**
* MsgTypeDistributionVO
* MsgTypeDistributionVOValue ObjectVO
* VO
*
*
* 便
*
* @author xcs
* @date 20240105 1525
**/
@Data
// @Data注解由Lombok库提供它的功能非常实用会自动为该类生成一系列常用的方法。
// 具体来说它会为类中的每一个私有属性自动生成对应的getter方法用于获取属性的值和setter方法用于设置属性的值
// 同时还会生成toString方法方便将对象以字符串形式展示常用于调试或者日志输出等场景能直观看到对象的属性值情况
// hashCode方法在涉及基于哈希的数据结构如HashMap等进行对象存储和查找等操作时会用到用于快速定位对象以及
// equals方法用于比较两个对象是否在逻辑上相等即属性值是否都相等通过使用这个注解大大简化了代码编写过程中
// 手动去编写这些重复且常规的方法的工作量,让代码更加简洁、易读和易维护。
@AllArgsConstructor
// @AllArgsConstructor注解同样来自Lombok库它会自动为这个类生成一个包含所有参数的构造函数。
// 例如对于这个MsgTypeDistributionVO类就会生成一个构造函数其参数顺序和类型与类中的属性声明顺序和类型一致
// 像这样public MsgTypeDistributionVO(String type, Integer value) {...}
// 这样在创建该类的对象实例时,就可以很方便地通过传入对应参数来完成对象的初始化,提高了代码的便利性和可读性,
// 尤其是当需要一次性为对象的多个属性赋值时不用再逐个调用setter方法来设置属性值了。
public class MsgTypeDistributionVO {
/**
*
* String
* "TEXT""IMAGE"
* 便
*/
private String type;
/**
*
* Integer
* 100"TEXT"
* value100便
*
*/
private Integer value;
}
}

@ -4,118 +4,193 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
/**
* MsgVO
* MsgVOValue ObjectVO
* 便访
*
*
* @author xcs
* @date 20231222 1443
**/
@Data
// @Data注解是由Lombok库提供的便捷注解它会自动为该类生成多个实用的方法具体如下
// - 自动生成所有私有属性对应的getter方法通过这些方法外部代码可以方便地获取类中各个属性的值
// 这在访问对象的具体属性信息时非常有用,例如获取消息的类型、内容等。
// - 自动生成所有私有属性对应的setter方法使得外部代码能够对类中的属性进行赋值操作
// 便于根据业务需求动态地修改对象的属性值,比如更新消息的创建时间、聊天者信息等。
// - 自动生成toString方法该方法将对象以一种易于阅读的字符串形式表示出来通常会包含类名以及各个属性的值
// 在调试程序时通过打印对象的toString结果可以快速直观地查看对象的具体状态了解各个属性的当前取值情况。
// - 自动生成hashCode方法这个方法在将对象存储到基于哈希的集合如HashMap、HashSet等中时会被用到
// 它根据对象的属性值计算出一个唯一的哈希码,用于确定对象在哈希集合中的存储位置,方便快速查找和比较对象。
// - 自动生成equals方法用于比较两个MsgVO对象是否在逻辑上相等即判断它们的所有属性值是否都完全相同
// 在涉及对象比较的业务逻辑中(如判断两条消息是否完全一致),该方法起着关键作用。
// 通过使用@Data注解大大减少了手动编写这些重复且基础的方法的工作量使代码更加简洁、易读和易维护。
public class MsgVO {
/**
*
*
* 1
* 使
*
*/
private Integer localId;
/**
* ID
* ID
* ID
* IDID
*
*/
private String msgSvrId;
/**
*
*
* 1234
*
*
*/
private Integer type;
/**
*
*
* type
* JPEGPNG
*
* 使
*/
private Integer subType;
/**
*
*
*
*
*
*
*/
private Long sequence;
/**
*
* 使10
*
*
*
*/
private Integer isSender;
/**
*
* 19701100:00:00 UTCUnix
*
*
*
*
*/
private Long createTime;
/**
*
* 便
* 使使"yyyy-MM-dd HH:mm:ss"
* -- ::
*
*/
private String strCreateTime;
/**
*
*
*
*
*
*
*/
private String strContent;
/**
*
*
*
* 便
*
*/
private String referMsgContent;
/**
*
*
* ID
* 便
* 使
*/
private String strTalker;
/**
*
*
*
* Base64
* 使
*/
private String avatar;
/**
* Md5
* Md5URLMD5
* MD5
* MD5
* MD5
*/
private String imgMd5;
/**
*
* 便
* Base64便使
*
*
*/
private String thumb;
/**
*
*
* Base64使
*
*
*/
private String image;
/**
* Url
* Url使
* Url
*
*/
private String emojiUrl;
/**
* compressContent
* compressContent
* @JsonIgnore
* JSONJavaJSONJSONJava
* JSONJSON
*
*/
@JsonIgnore
private byte[] compressContent;
/**
* bytesExtra
* bytesExtra
* IP
* compressContent@JsonIgnoreJSON
* 使
*/
@JsonIgnore
private byte[] bytesExtra;
/**
*
* WeAppInfoVOWeAppInfoVO
* MsgVOweAppInfo便ID
*
* WeAppInfoVO
* 便
*/
private WeAppInfoVO weAppInfo;
/**
*
* CardLinkVOCardLinkVO
*
*
* CardLinkVO便
*
*/
private CardLinkVO cardLink;
private CardLinkVO cardLink;}
/**
* Id
*/
private String wxId;
}

@ -2,36 +2,65 @@ package com.xcs.wx.domain.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.List;
/**
* PageVO
* PageVOValue ObjectVO
* 使 <T>使
* 访
*
*
* @author xcs
* @date 20231229 1619
**/
@Data
// @Data注解由Lombok库提供它会自动为这个类生成一系列实用的方法具体包括
// - 为类中的每一个私有属性自动生成对应的getter方法方便外部代码获取各个属性的值。例如在其他类中可以通过调用getCurrent()方法获取当前页数,
// 调用getPageSize()方法获取每页显示的数据条数等,这有助于对分页相关属性进行访问和使用。
// - 自动生成所有私有属性对应的setter方法使得外部代码能够根据业务需求动态地修改对象的属性值。比如根据用户的选择改变当前页数或者每页显示的数量等
// 增强了对象属性值的可修改性和灵活性。
// - 生成toString方法该方法能将PageVO对象以一种直观、易于阅读的字符串形式展示出来通常会包含类名以及各个属性的值
// 在调试程序时通过打印对象的toString结果可以快速查看当前分页对象的具体状态了解各个分页属性的取值情况便于排查问题。
// - 生成hashCode方法在将PageVO对象存储到基于哈希的集合如HashMap、HashSet等中时会用到这个方法
// 它依据对象的属性值计算出一个唯一的哈希码,用于确定对象在哈希集合中的存储位置,方便在集合中快速查找和比较对象。
// - 生成equals方法用于比较两个PageVO对象是否在逻辑上相等也就是判断它们的所有属性值是否都完全相同
// 在涉及分页数据比较的业务逻辑中(如判断两个分页结果是否一致),该方法能准确地进行对象的相等性判断。
// 通过使用@Data注解大大减少了手动编写这些常规方法的工作量让代码更加简洁、易读且易于维护。
@AllArgsConstructor
// @AllArgsConstructor注解同样来自Lombok库它会自动为这个类生成一个包含所有参数的构造函数。
// 对于PageVO类来说这个构造函数的参数顺序和类型与类中的属性声明顺序和类型是一一对应的
// 即构造函数形如public PageVO(Long current, Long pageSize, Long total, List<T> records) {...}。
// 这样在创建PageVO对象实例时就可以很方便地一次性传入当前页数、页数大小、总页数以及查询结果数据列表这些参数来完成对象的初始化
// 提高了代码创建分页对象的便利性和可读性尤其是在需要同时为多个属性赋值时避免了逐个调用setter方法来设置属性值的繁琐操作。
public class PageVO<T> {
/**
*
* 11
* 3
*
* 便
*/
private Long current;
/**
*
* 1010
*
* 便
*/
private Long pageSize;
/**
*
*
* 1001010
*
*
*/
private Long total;
/**
*
* 使List<T>T
* TUserVO
* TProductVO
* 便
*/
private List<T> records;
}
}

@ -4,17 +4,38 @@ import lombok.AllArgsConstructor;
import lombok.Data;
/**
* RecentUsedKeyWordVO
* RecentUsedKeyWordVOValue ObjectVO使
* VO便
*
*
* @author xcs
* @date 20240123 1127
**/
@Data
// @Data注解由Lombok库提供它为该类自动生成了多个常用的方法具体如下
// - 自动生成对应的getter方法通过这个方法名为getText())可以方便地从对象中获取关键字的字符串内容,
// 在其他类需要访问这个关键字信息时,只需调用该方法即可,使得对关键字属性的访问更加便捷、规范。
// - 自动生成对应的setter方法名为setText(String text)),允许外部代码根据业务需求对关键字进行修改,
// 例如当用户输入了新的最近使用关键字时可以通过调用这个setter方法来更新对象中的关键字内容增强了对象属性的可操作性。
// - 生成toString方法该方法能将RecentUsedKeyWordVO对象以一种直观、易于阅读的字符串形式展示出来通常会包含类名以及关键字的具体值
// 在调试程序或者记录日志等场景下通过打印对象的toString结果可以快速查看当前关键字的具体情况有助于排查问题和了解对象状态。
// - 生成hashCode方法在将对象存储到基于哈希的集合如HashMap、HashSet等中时会用到这个方法
// 它根据对象的关键字属性值计算出一个唯一的哈希码,用于确定对象在哈希集合中的存储位置,方便快速查找和比较对象。
// - 生成equals方法用于比较两个RecentUsedKeyWordVO对象是否在逻辑上相等也就是判断它们所包含的关键字内容是否完全相同
// 在涉及关键字比较的业务逻辑中(比如判断两个最近使用的关键字是否一致),该方法能准确地进行对象的相等性判断。
// 通过使用@Data注解大大减少了手动编写这些常规方法的工作量让代码更加简洁、易读且易于维护。
@AllArgsConstructor
// @AllArgsConstructor注解同样来自Lombok库它会自动为这个类生成一个包含所有参数的构造函数
// 对于RecentUsedKeyWordVO类而言构造函数的形式为public RecentUsedKeyWordVO(String text) {...}
// 这意味着在创建该类的对象实例时,只需要传入表示关键字的字符串参数即可完成对象的初始化,操作非常简便,
// 提高了创建对象时传递关键字数据的便利性和代码的可读性,使得代码在实例化这类对象时更加简洁明了。
public class RecentUsedKeyWordVO {
/**
*
* String
* 使
* 使便
* 使
*/
private String text;
}
}

@ -6,38 +6,63 @@ import com.alibaba.excel.annotation.write.style.ColumnWidth;
import lombok.Data;
/**
* RecoverContactVO
* RecoverContactVOValue ObjectVO
* Excel使
* 使
*
* @author xcs
* @date 202461415:29:54
**/
@Data
// @Data注解由Lombok库提供它会自动为这个类生成一系列实用的方法具体包括
// - 自动生成所有私有属性对应的getter方法方便外部代码获取各个属性的值例如通过调用getDocId()、getAlias()等方法来获取相应属性内容,
// 这有助于在其他类中访问RecoverContactVO对象的具体属性信息。
// - 自动生成所有私有属性对应的setter方法使得外部代码能够根据业务需求动态地修改对象的属性值比如可以通过调用setAlias(String alias)等方法来更新属性值,
// 增强了对象属性的可操作性,便于数据的动态变化和处理。
// - 生成toString方法该方法能将RecoverContactVO对象以一种直观、易于阅读的字符串形式展示出来通常会包含类名以及各个属性的值
// 在调试程序时通过打印对象的toString结果可以快速查看当前对象的具体状态了解各个属性的取值情况便于排查问题。
// - 生成hashCode方法在将对象存储到基于哈希的集合如HashMap、HashSet等中时会用到这个方法
// 它依据对象的属性值计算出一个唯一的哈希码,用于确定对象在哈希集合中的存储位置,方便在集合中快速查找和比较对象。
// - 生成equals方法用于比较两个RecoverContactVO对象是否在逻辑上相等也就是判断它们的所有属性值是否都完全相同
// 在涉及对象比较的业务逻辑中(如判断两个联系人信息是否一致),该方法能准确地进行对象的相等性判断。
// 通过使用@Data注解大大减少了手动编写这些常规方法的工作量让代码更加简洁、易读且易于维护。
public class RecoverContactVO {
/**
*
*
* 1
* 便
* 使@ExcelIgnore使Excel
* ExcelExcel
*
*/
@ExcelIgnore
private Integer docId;
/**
* alias
* alias使@ExcelPropertyExcel
* 使ExcelRecoverContactVOExcel
* 使@ColumnWidth50Excel50Excel
* Excel使便
*/
@ExcelProperty("微信号")
@ColumnWidth(50)
private String alias;
/**
* nickname
* nickname@ExcelPropertyExcel
* Excel便
* 使@ColumnWidth100Excel
*/
@ExcelProperty("昵称")
@ColumnWidth(100)
private String nickname;
/**
* c2remark
* c2remark使@ExcelPropertyExcel
* 使Excel便
* @ColumnWidth(100)Excel
*/
@ExcelProperty("备注")
@ColumnWidth(100)
private String remark;
}
}

@ -3,55 +3,86 @@ package com.xcs.wx.domain.vo;
import lombok.Data;
/**
* ResponseVO
* ResponseVOValue ObjectVO
* JSON
* 使便
*
* @author xcs
* @date 20231225 1731
* &#064;date 20231225 1731
**/
@Data
// @Data注解由Lombok库提供它会自动为这个类生成一系列实用的方法具体如下
// - 为类中的每一个私有属性自动生成对应的getter方法方便外部代码获取各个属性的值例如可以通过调用getSuccess()获取业务编码状态,
// 通过getErrorCode()获取错误编码等,便于对响应结果中的各部分信息进行访问和后续处理。
// - 自动生成所有私有属性对应的setter方法使得外部代码能够根据业务需求动态地修改对象的属性值比如在构建响应对象时
// 通过调用setSuccess(boolean success)方法来设置业务是否成功等,增强了对象属性值的可修改性和灵活性。
// - 生成toString方法该方法能将ResponseVO对象以一种直观、易于阅读的字符串形式展示出来通常会包含类名以及各个属性的值
// 在调试程序时通过打印对象的toString结果可以快速查看当前响应对象的具体状态了解各个属性的取值情况便于排查问题。
// - 生成hashCode方法在将对象存储到基于哈希的集合如HashMap、HashSet等中时会用到这个方法
// 它依据对象的属性值计算出一个唯一的哈希码,用于确定对象在哈希集合中的存储位置,方便在集合中快速查找和比较对象。
// - 生成equals方法用于比较两个ResponseVO对象是否在逻辑上相等也就是判断它们的所有属性值是否都完全相同
// 在涉及响应结果比较的业务逻辑中(如判断两次相同操作的响应是否一致),该方法能准确地进行对象的相等性判断。
// 通过使用@Data注解大大减少了手动编写这些常规方法的工作量让代码更加简洁、易读且易于维护。
public class ResponseVO<T> {
/**
*
* 使Booleantruefalse
* 便
*
*/
private Boolean success;
/**
*
* Integer
* Web10011002便
*
*/
private Integer errorCode;
/**
*
* String
* 便
*
*/
private String errorMessage;
/**
*
* 使
* 便
* 1total使
*/
private Long page;
/**
*
* 使page
* 便100210
*
*/
private Long total;
/**
*
* 使
* 12
*
*/
private Integer showType;
/**
*
* T
* TUserVO
* TProductVO
*/
private T data;
/**
*
* 便ResponseVO
* dataResponseVO
* successtruedataResponseVO
* 便
*
* @param data
* @param <T>
* @return ResponseDTO
* @param data T
* @param <T> 使
* @return ResponseVO<T>ResponseVO
*/
public static <T> ResponseVO<T> ok(T data) {
ResponseVO<T> wrapper = new ResponseVO<>();
@ -61,13 +92,16 @@ public class ResponseVO<T> {
}
/**
*
* ok(T data)pagetotal
* datapagetotal
* ResponseVOtruedatapagetotal
* 便
*
* @param data
* @param <T>
* @param page
* @param total
* @return ResponseDTO
* @param data T
* @param <T> 使
* @param page 1
* @param total page
* @return ResponseVO<T>ResponseVO
*/
public static <T> ResponseVO<T> ok(T data, Long page, Long total) {
ResponseVO<T> wrapper = new ResponseVO<>();
@ -79,10 +113,15 @@ public class ResponseVO<T> {
}
/**
*
* ResponseVOerrorCodeerrorMessage
* 便ResponseVO
* successfalseerrorCodeerrorMessage
* showType2ResponseVO
* 使便便
*
* @param <T>
* @return ResponseDTO
* @param <T> 使
* ResponseVOT
* @return ResponseVO<T>ResponseVO
*/
public static <T> ResponseVO<T> error(Integer errorCode, String errorMessage) {
ResponseVO<T> wrapper = new ResponseVO<>();
@ -92,4 +131,4 @@ public class ResponseVO<T> {
wrapper.setErrorMessage(errorMessage);
return wrapper;
}
}
}

@ -3,41 +3,66 @@ package com.xcs.wx.domain.vo;
import lombok.Data;
/**
* SessionVO
* SessionVOValue ObjectVO
* 线便
*
*
* @author xcs
* @date 20231221 1813
* &#064;date 20231221 1813
**/
@Data
// @Data注解由Lombok库提供它会自动为这个类生成一系列实用的方法具体如下
// - 自动生成所有私有属性对应的getter方法通过这些方法例如getUserName()、getNickName()等),外部代码可以方便地获取类中各个属性的值,
// 这在访问会话相关的具体属性信息时非常有用,比如在展示会话信息时获取用户名、用户昵称等内容。
// - 自动生成所有私有属性对应的setter方法使得外部代码能够对类中的属性进行赋值操作便于根据业务需求动态地修改对象的属性值
// 例如当用户更新了昵称就可以通过调用setNickName(String newNickName)方法来更新nickName属性的值。
// - 生成toString方法该方法能将SessionVO对象以一种直观、易于阅读的字符串形式展示出来通常会包含类名以及各个属性的值
// 在调试程序时通过打印对象的toString结果可以快速查看当前会话对象的具体状态了解各个属性的取值情况便于排查问题。
// - 生成hashCode方法这个方法在将对象存储到基于哈希的集合如HashMap、HashSet等中时会被用到
// 它根据对象的属性值计算出一个唯一的哈希码,用于确定对象在哈希集合中的存储位置,方便快速查找和比较对象。
// - 生成equals方法用于比较两个SessionVO对象是否在逻辑上相等即判断它们的所有属性值是否都完全相同
// 在涉及会话对象比较的业务逻辑中(如判断两个会话是否为同一用户、同一时间等情况),该方法起着关键作用。
// 通过使用@Data注解大大减少了手动编写这些重复且基础的方法的工作量使代码更加简洁、易读和易维护。
public class SessionVO {
/**
*
* String
*
*
*/
private String userName;
/**
*
*
* 便
*
*/
private String nickName;
/**
*
*
*
*/
private String content;
/**
*
* IntegerUnix19701100:00:00 UTC
*
* 便
*/
private Integer time;
/**
*
*
* 10:301030 15:20便
* 便
*/
private String shortTime;
/**
* Url
* Url
* 使
*
*/
private String headImgUrl;
}
}

@ -4,32 +4,59 @@ import lombok.AllArgsConstructor;
import lombok.Data;
/**
* StatsPanelVO
* StatsPanelVOValue ObjectVO
*
* 便便
*
* @author xcs
* @date 20240123 1725
* &#064;date 20240123 1725
**/
@Data
// @Data注解由Lombok库提供它会自动为这个类生成一系列实用的方法具体如下
// - 自动生成所有私有属性对应的getter方法通过这些方法例如getContact()、getChatRoom()等),外部代码可以方便地获取类中各个属性的值,
// 这在访问统计面板相关的具体属性信息时非常有用,比如在前端页面展示统计数据时获取联系人数量、群聊数量等内容,便于进行数据展示和后续处理。
// - 自动生成所有私有属性对应的setter方法使得外部代码能够对类中的属性进行赋值操作便于根据业务需求动态地修改对象的属性值
// 例如当有新的联系人添加或者消息收发情况发生变化时可以通过调用相应的setter方法来更新对象中的属性值增强了对象属性的可操作性和灵活性。
// - 生成toString方法该方法能将StatsPanelVO对象以一种直观、易于阅读的字符串形式展示出来通常会包含类名以及各个属性的值
// 在调试程序时通过打印对象的toString结果可以快速查看当前统计面板对象的具体状态了解各个属性的取值情况便于排查问题。
// - 生成hashCode方法在将对象存储到基于哈希的集合如HashMap、HashSet等中时会用到这个方法
// 它依据对象的属性值计算出一个唯一的哈希码,用于确定对象在哈希集合中的存储位置,方便在集合中快速查找和比较对象。
// - 生成equals方法用于比较两个StatsPanelVO对象是否在逻辑上相等也就是判断它们的所有属性值是否都完全相同
// 在涉及统计数据比较的业务逻辑中(如判断不同时间段或者不同用户的统计面板数据是否一致),该方法能准确地进行对象的相等性判断。
// 通过使用@Data注解大大减少了手动编写这些常规方法的工作量让代码更加简洁、易读且易于维护。
@AllArgsConstructor
// @AllArgsConstructor注解同样来自Lombok库它会自动为这个类生成一个包含所有参数的构造函数
// 对于StatsPanelVO类而言构造函数的形式为public StatsPanelVO(Integer contact, Integer chatRoom, Integer sent, Integer received) {...}
// 这意味着在创建该类的对象实例时,只需要依次传入表示联系人数量、群聊数量、今日发送消息数量以及今日接收消息数量的整数参数,即可完成对象的初始化,
// 操作非常简便,提高了创建对象时传递统计数据的便利性和代码的可读性,使得代码在实例化这类对象时更加简洁明了。
public class StatsPanelVO {
/**
*
* 使Integer
*
*
*/
private Integer contact;
/**
*
*
*
* 便
*/
private Integer chatRoom;
/**
*
*
*
* 使
*/
private Integer sent;
/**
*
*
*
*
/
*/
private Integer received;
}
}

@ -3,31 +3,53 @@ package com.xcs.wx.domain.vo;
import lombok.Data;
/**
* TopContactsVO
* TopContactsVOValue ObjectVO
* 便
* 使便
*
* @author xcs
* @date 20240106 1538
* &#064;date 20240106 1538
**/
@Data
// @Data注解由Lombok库提供它会自动为这个类生成一系列实用的方法具体作用如下
// - 自动生成所有私有属性对应的getter方法例如通过调用getUserName()、getNickName()等方法,外部代码可以方便地获取类中各个属性的值,
// 这在需要访问联系人的具体属性信息时非常有用,比如在前端页面展示联系人信息时获取用户名、昵称等内容,便于数据的展示和使用。
// - 自动生成所有私有属性对应的setter方法使得外部代码能够根据业务需求动态地修改对象的属性值例如当联系人更新了昵称
// 可以通过调用setNickName(String newNickName)方法来更新nickName属性的值增强了对象属性的可操作性和灵活性。
// - 生成toString方法该方法能将TopContactsVO对象以一种直观、易于阅读的字符串形式展示出来通常会包含类名以及各个属性的值
// 在调试程序时通过打印对象的toString结果可以快速查看当前对象所代表的联系人的具体状态了解各个属性的取值情况便于排查问题。
// - 生成hashCode方法在将对象存储到基于哈希的集合如HashMap、HashSet等中时会用到这个方法
// 它依据对象的属性值计算出一个唯一的哈希码,用于确定对象在哈希集合中的存储位置,方便在集合中快速查找和比较对象。
// - 生成equals方法用于比较两个TopContactsVO对象是否在逻辑上相等也就是判断它们的所有属性值是否都完全相同
// 在涉及联系人对象比较的业务逻辑中(如判断两个联系人是否为同一人等情况),该方法能准确地进行对象的相等性判断。
// 通过使用@Data注解大大减少了手动编写这些常规方法的工作量让代码更加简洁、易读且易于维护。
public class TopContactsVO {
/**
*
* String
*
* TopContactsVO
*/
private String userName;
/**
*
*
* 便
*
*/
private String nickName;
/**
*
*
*
* 使
*/
private String headImgUrl;
/**
* total
* total使Long
*
* 便
*/
private Long total;
}
}

@ -3,41 +3,68 @@ package com.xcs.wx.domain.vo;
import lombok.Data;
/**
* UserInfoVO
* UserInfoVOValue ObjectVO
*
* 使
* 便
*
* @author xcs
* @date 202462816:13:53
* &#064;date 202462816:13:53
*/
@Data
// @Data注解由Lombok库提供它会自动为这个类生成一系列实用的方法具体如下
// - 自动生成所有私有属性对应的getter方法像通过调用getBasePath()、getWxId()等方法,外部代码可以方便地获取类中各个属性的值,
// 这在需要访问用户具体属性信息时非常有用比如在展示用户详情页面时获取文件目录、微信Id等内容便于数据展示与后续使用。
// - 自动生成所有私有属性对应的setter方法使得外部代码能够根据业务需求动态地修改对象的属性值例如当用户更新了手机号
// 可以通过调用setMobile(String newMobile)方法来更新mobile属性的值增强了对象属性的可操作性和灵活性。
// - 生成toString方法该方法能将UserInfoVO对象以一种直观、易于阅读的字符串形式展示出来通常会包含类名以及各个属性的值
// 在调试程序时通过打印对象的toString结果可以快速查看当前用户信息对象的具体状态了解各个属性的取值情况便于排查问题。
// - 生成hashCode方法在将对象存储到基于哈希的集合如HashMap、HashSet等中时会用到这个方法
// 它依据对象的属性值计算出一个唯一的哈希码,用于确定对象在哈希集合中的存储位置,方便在集合中快速查找和比较对象。
// - 生成equals方法用于比较两个UserInfoVO对象是否在逻辑上相等也就是判断它们的所有属性值是否都完全相同
// 在涉及用户对象比较的业务逻辑中(如判断两个用户信息是否一致),该方法能准确地进行对象的相等性判断。
// 通过使用@Data注解大大减少了手动编写这些常规方法的工作量让代码更加简洁、易读且易于维护。
public class UserInfoVO {
/**
*
* String
*
*
*/
private String basePath;
/**
* Id
* Id使
* Id
* Id
*/
private String wxId;
/**
*
*
* 便
*
*/
private String nickname;
/**
*
* 使
* 1.0.1便
*
*/
private String version;
/**
*
*
*
*
*/
private String account;
/**
*
*
*
/
*/
private String mobile;
}
}

@ -4,32 +4,58 @@ import lombok.AllArgsConstructor;
import lombok.Data;
/**
* UserVO
*
* UserVOValue ObjectVO
*
* 使便
* @author xcs
* @date 2023121020:21:02
* &#064;date 2023121020:21:02
*/
@Data
// @Data注解由Lombok库提供它会自动为这个类生成一系列实用的方法具体作用如下
// - 自动生成所有私有属性对应的getter方法例如通过调用getWxId()、getNickname()等方法,外部代码能够方便地获取类中各个属性的值,
// 在需要展示用户信息、根据用户属性进行相关业务逻辑判断等场景下这些getter方法能便捷地提供对应属性的数据访问途径。
// - 自动生成所有私有属性对应的setter方法使得外部代码可以根据业务需求动态地修改对象的属性值比如当用户更新了昵称
// 可以通过调用setNickname(String newNickname)方法来更新nickname属性的值从而保证对象属性能够灵活地反映用户数据的变化。
// - 生成toString方法该方法会将UserVO对象以一种直观、易于阅读的字符串形式展示出来通常包含类名以及各个属性的值
// 在调试程序时通过打印对象的toString结果可以快速查看当前用户对象的具体状态了解各个属性的取值情况便于排查问题。
// - 生成hashCode方法在将对象存储到基于哈希的集合如HashMap、HashSet等中时会用到这个方法
// 它依据对象的属性值计算出一个唯一的哈希码,用于确定对象在哈希集合中的存储位置,方便在集合中快速查找和比较对象。
// - 生成equals方法用于比较两个UserVO对象是否在逻辑上相等也就是判断它们的所有属性值是否都完全相同
// 在涉及用户对象比较的业务逻辑中(如判断两个用户是否为同一人、状态是否一致等情况),该方法能够准确地进行对象的相等性判断。
// 通过使用@Data注解大大减少了手动编写这些常规方法的工作量让代码更加简洁、易读且易于维护。
@AllArgsConstructor
// @AllArgsConstructor注解同样来自Lombok库它会自动为这个类生成一个包含所有参数的构造函数
// 对于UserVO类而言构造函数的形式为public UserVO(String wxId, String nickname, String avatar, boolean current) {...}
// 这意味着在创建该类的对象实例时只需要依次传入微信IdwxId、昵称nickname、头像avatar以及当前选中状态current这些参数
// 即可完成对象的初始化操作,这种方式提高了创建用户对象时传递数据的便利性和代码的可读性,使代码在实例化该类对象时更加简洁明了。
public class UserVO {
/**
* wxId
* wxIdString使
*
*
*/
private String wxId;
/**
*
*
*
*
*/
private String nickname;
/**
*
*
*
* 使
*/
private String avatar;
/**
*
* 使boolean
* truefalse
* 便
*/
private boolean current;
}
}

@ -3,31 +3,53 @@ package com.xcs.wx.domain.vo;
import lombok.Data;
/**
* WeAppInfoVO
*
* WeAppInfoVOValue ObjectVOWeApp
* 便
* 便
* @author xcs
* @date 20240117 1419
* &#064;date 20240117 1419
**/
@Data
// @Data注解由Lombok库提供它会自动为这个类生成一系列实用的方法具体如下
// - 自动生成所有私有属性对应的getter方法像通过调用getTitle()、getSourceDisplayName()等方法,外部代码可以方便地获取类中各个属性的值,
// 在需要展示小程序信息例如在前端页面呈现小程序的标题、来源显示名称等内容时这些getter方法能便捷地提供对应属性的数据访问途径便于信息展示。
// - 自动生成所有私有属性对应的setter方法使得外部代码能够根据业务需求动态地修改对象的属性值比如当小程序的标题发生变化
// 可以通过调用setTitle(String newTitle)方法来更新title属性的值保证对象属性能够灵活地反映小程序相关信息的变化增强了属性的可操作性。
// - 生成toString方法该方法能将WeAppInfoVO对象以一种直观、易于阅读的字符串形式展示出来通常会包含类名以及各个属性的值
// 在调试程序时通过打印对象的toString结果可以快速查看当前小程序信息对象的具体状态了解各个属性的取值情况便于排查问题。
// - 生成hashCode方法在将对象存储到基于哈希的集合如HashMap、HashSet等中时会用到这个方法
// 它依据对象的属性值计算出一个唯一的哈希码,用于确定对象在哈希集合中的存储位置,方便在集合中快速查找和比较对象。
// - 生成equals方法用于比较两个WeAppInfoVO对象是否在逻辑上相等也就是判断它们的所有属性值是否都完全相同
// 在涉及小程序信息比较的业务逻辑中(如判断两个小程序的相关属性是否一致),该方法能准确地进行对象的相等性判断。
// 通过使用@Data注解大大减少了手动编写这些常规方法的工作量让代码更加简洁、易读且易于维护。
public class WeAppInfoVO {
/**
* title
* titleString
*
* 便
*/
private String title;
/**
* sourceDisplayName
* sourceDisplayName
*
/
*/
private String sourceDisplayName;
/**
* weAppIconUrl
* weAppIconUrl
* 使
//是小程序信息展示中重要的可视化元素相关属性。
*/
private String weAppIconUrl;
/**
* weAppPageThumbRawUrl
* weAppPageThumbRawUrl
//或者查看小程序特定页面的预览图时,通过这个链接可以获取到相应页面的缩略图进行展示,让用户提前了解页面的大致内容和布局,
//是用于呈现小程序页面相关视觉信息的重要属性,有助于提升用户对小程序页面内容的认知和交互体验。
*/
private String weAppPageThumbRawUrl;
}
}

@ -5,53 +5,94 @@ import lombok.Data;
import lombok.RequiredArgsConstructor;
/**
* WeChatConfigVO
*
* WeChatConfigVOValue ObjectVO
*
* 便
* 便
* @author xcs
* @date 20231225 0938
* &#064;date 20231225 0938
**/
@Data
// @Data注解由Lombok库提供它会自动为这个类生成一系列实用的方法具体如下
// - 自动生成所有私有属性对应的getter方法例如通过调用getPid()、getBaseAddress()等方法,外部代码可以方便地获取类中各个属性的值,
// 在需要访问微信配置的具体属性信息时比如查看进程Id、基址等内容这些getter方法能提供便捷的数据访问途径便于后续业务逻辑使用这些数据。
// - 自动生成所有私有属性对应的setter方法使得外部代码能够根据业务需求动态地修改对象的属性值例如当微信账号发生变更
// 可以通过调用setAccount(String newAccount)方法来更新account属性的值从而保证对象的属性能够灵活地反映微信配置信息的实际变化情况增强了属性的可操作性。
// - 生成toString方法该方法能将WeChatConfigVO对象以一种直观、易于阅读的字符串形式展示出来通常会包含类名以及各个属性的值
// 在调试程序时通过打印对象的toString结果可以快速查看当前微信配置对象的具体状态了解各个属性的取值情况便于排查问题。
// - 生成hashCode方法在将对象存储到基于哈希的集合如HashMap、HashSet等中时会用到这个方法
// 它依据对象的属性值计算出一个唯一的哈希码,用于确定对象在哈希集合中的存储位置,方便在集合中快速查找和比较对象。
// - 生成equals方法用于比较两个WeChatConfigVO对象是否在逻辑上相等也就是判断它们的所有属性值是否都完全相同
// 在涉及微信配置对象比较的业务逻辑中(如判断不同环境下微信配置是否一致等情况),该方法能准确地进行对象的相等性判断。
// 通过使用@Data注解大大减少了手动编写这些常规方法的工作量让代码更加简洁、易读且易于维护。
@RequiredArgsConstructor
// @RequiredArgsConstructor注解同样来自Lombok库它会基于类中被声明为final的非空字段自动生成一个构造函数
// 要求在创建对象实例时,必须传入这些被标记为必需的参数,以此保证对象在初始化时关键属性有值,增强了对象创建的规范性和数据完整性。
@AllArgsConstructor
// @AllArgsConstructor注解也由Lombok库提供它会自动为这个类生成一个包含所有参数的构造函数
// 即构造函数的形式为public WeChatConfigVO(Integer pid, Long baseAddress, String version, String nickname, String account, String mobile, String basePath, String wxId) {...}
// 这意味着在创建该类的对象实例时只需要依次传入进程Idpid、基址baseAddress、版本号version、昵称nickname、账号account
// 手机号mobile、文件目录basePath以及微信IdwxId这些参数即可完成对象的初始化操作这种方式提高了创建对象时传递微信配置数据的便利性和代码的可读性
// 使代码在实例化该类对象时更加简洁明了,不过需要注意同时使用@RequiredArgsConstructor和@AllArgsConstructor时要根据实际情况合理使用构造函数。
public class WeChatConfigVO {
/**
* Id
* Id使IntegerId
//通过这个Id可以对微信进程进行管理、监控以及与其他进程进行交互等操作例如判断微信进程是否正常运行、获取其资源占用情况等
//是在涉及微信运行状态管理以及与系统层面交互时重要的基础属性之一。
*/
private Integer pid;
/**
*
* Long
//它通常指的是微信程序在内存中的起始地址,通过这个基址可以进一步定位和访问微信程序在内存中的其他数据结构、模块等,
//对于一些涉及微信内存数据读取、修改以及与底层代码交互的高级操作(比如插件开发、逆向分析等情况),基址是关键的参考信息之一。
*/
private Long baseAddress;
/**
*
* String8.0.1
//版本号用于区分不同阶段发布的微信版本,方便进行版本管理、功能更新提示以及兼容性判断等操作,
//在涉及微信升级、不同版本间功能差异处理、与其他系统或插件的兼容性适配等业务场景中,版本号是重要的参考依据,
//确保系统能根据微信的版本情况准确地提供相应服务或进行相应的业务逻辑调整。
*/
private String version;
/**
*
*
//在微信的社交互动场景中,如聊天界面、好友列表展示等,昵称往往更能直观地让其他用户识别是谁,相比于账号等相对固定且较为正式的标识,
//昵称更具亲和力,是体现用户个性化以及方便用户之间交互识别的重要属性之一。
*/
private String nickname;
/**
*
*
//是用户进入微信、获取相应服务的重要“钥匙”,在微信的用户登录、权限管理以及涉及用户身份验证的诸多业务逻辑中起着核心的标识作用。
*/
private String account;
/**
*
*
//还常用于身份验证(如接收验证码进行注册、登录、修改重要信息等操作)、消息通知(如接收微信推送的短信提醒)以及关联其他服务(如与手机号绑定的第三方账号授权等),
//是与用户联系紧密且具有多种重要用途的关键属性,在涉及微信用户安全验证、信息推送以及多平台账号整合等业务场景中有着重要地位。
*/
private String mobile;
/**
*
*
//例如存储聊天记录文件、缓存文件、用户自定义配置文件等的文件夹所在位置,也可以是网络存储中与微信相关文件的特定路径(在一些特殊的企业级应用或者云服务场景下),
//它用于定位和管理与微信相关的各类文件,是涉及微信文件操作以及数据管理时的重要属性之一。
*/
private String basePath;
/**
* Id
* Id
//通过这个Id可以在微信的服务器端、客户端等进行用户的精准定位、数据关联以及各种业务操作
//在整合微信相关功能或者基于微信账号进行用户认证、信息同步等业务场景中微信Id是关键的用户标识属性。
*/
private String wxId;
}
}

@ -5,21 +5,50 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* BaseExceptionJava `RuntimeException`
* 便
* `com.xcs.wx` 使便
* @author xcs
* @date 20231225 1739
* &#064;date 20231225 1739
**/
@Data
// @Data注解由Lombok库提供它会自动为这个类生成一系列实用的方法具体如下
// - 自动生成所有私有属性对应的getter方法通过调用 `getCode()` 和 `getMsg()` 方法,外部代码可以方便地获取类中定义的错误编码和错误消息这两个属性的值,
// 在捕获该异常并进行处理时,能够便捷地获取异常所携带的具体错误信息,便于后续根据这些信息进行日志记录、向用户反馈或者执行相应的错误处理逻辑等操作。
// - 自动生成所有私有属性对应的setter方法使得外部代码在某些特定场景下虽然在异常场景中相对少见但理论上存在需求
// 能够动态地修改对象的属性值,不过对于异常类来说,通常更多是在创建异常实例时就确定好属性值,用于准确反映异常发生时的情况。
// - 生成toString方法该方法能将 `BaseException` 对象以一种直观、易于阅读的字符串形式展示出来,通常会包含类名以及各个属性的值,
// 在调试程序时通过打印对象的toString结果可以快速查看当前异常对象的具体状态了解错误编码和错误消息的取值情况便于排查问题。
// - 生成hashCode方法在将对象存储到基于哈希的集合如HashMap、HashSet等中时会用到这个方法
// 它依据对象的属性值计算出一个唯一的哈希码,用于确定对象在哈希集合中的存储位置,不过在异常处理场景中,将异常对象放入此类集合的情况相对不那么常见。
// - 生成equals方法用于比较两个 `BaseException` 对象是否在逻辑上相等,也就是判断它们的所有属性值是否都完全相同,
// 在一些涉及异常比较的特定业务逻辑(虽然比较少见)中,该方法能准确地进行对象的相等性判断。
@AllArgsConstructor
// @AllArgsConstructor注解同样来自Lombok库它会自动为这个类生成一个包含所有参数的构造函数
// 在这里就会生成一个构造函数形式为 `public BaseException(Integer code, String msg)`
// 意味着在创建 `BaseException` 类的实例时,必须传入错误编码(`code`)和错误消息(`msg`)这两个参数,
// 这样可以方便地按照业务中出现的具体错误情况,准确地实例化异常对象,使其携带对应的错误信息,便于后续的异常抛出和处理流程。
@EqualsAndHashCode(callSuper = true)
// @EqualsAndHashCode注解用于生成 `equals` 和 `hashCode` 方法,这里 `callSuper = true` 表示在生成这两个方法时,
// 会同时考虑父类(即 `RuntimeException`)的相关属性来进行相等性判断和哈希码的计算,确保在进行对象比较和哈希操作时,
// 不仅考虑了本类中定义的 `code` 和 `msg` 属性,也兼顾了父类的状态,使得对象比较和哈希处理更加全面、准确,符合继承体系下的逻辑要求。
public class BaseException extends RuntimeException {
/**
*
* 使Integer
// 不同的业务模块或者功能出现问题时,可以分配不同的错误编码,通过这个编码可以快速在代码中定位到具体是哪种错误发生了,
// 例如可以在项目的错误码手册或者配置文件中定义好每个编码对应的具体错误含义,方便开发人员快速识别和处理相应的异常情况,实现统一的错误管理。
*/
private Integer code;
/**
*
* String
// 这个消息通常会以比较通俗易懂的语言呈现给开发人员(在查看日志等场景下)或者最终用户(在进行友好的错误提示时),
// 让他们能够清楚地了解为什么会出现这个异常情况,例如可以是“用户名已存在,请重新输入”之类的提示性消息,便于采取相应的解决措施。
*/
private String msg;
}
}

@ -2,13 +2,23 @@ package com.xcs.wx.exception;
/**
*
* BaseException
* 便便
*
* @author xcs
* @date 20231225 1738
* &#064;date 20231225 1738
**/
public class BizException extends BaseException {
/**
* BizException
* BaseException
* 使便
*
* @param code
* @param msg
*/
public BizException(Integer code, String msg) {
super(code, msg);
}
}
}

@ -5,9 +5,15 @@ import com.xcs.wx.domain.ChatRoomInfo;
/**
* Mapper
* ChatRoomInfoMyBatis PlusBaseMapper
* MyBatis PlusCRUD
* 便
*
* @author xcs
* @date 20240109 1520
* &#064;date 20240109 1520
**/
public interface ChatRoomInfoMapper extends BaseMapper<ChatRoomInfo> {
}
// 目前该接口直接继承BaseMapper没有额外自定义的方法。
// 但如果后续业务中有针对群聊详情表特有的复杂查询、关联查询或者其他数据库操作逻辑,
// 可以在这里添加相应的抽象方法声明然后在对应的Mapper实现类中去具体实现这些方法以满足业务需求。
}

@ -11,33 +11,48 @@ import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* Mapper
*
* ChatRoomMapperMyBatis Plus `BaseMapper`
* MyBatis Plus便
* 便
* @author xcs
* @date 20240108 1555
* &#064;date 20240108 1555
**/
public interface ChatRoomMapper extends BaseMapper<ChatRoom> {
/**
*
* `ChatRoomVO`
* `ChatRoomVO` 使
* 使
*
* @param page
* @param chatRoomDTO
* @return ChatRoomVO
* @param page MyBatis Plus `Page`
// 这样在查询数据库时就能按照设定的分页规则准确获取对应的数据,方便在前端页面或者其他业务场景中进行分页展示群聊列表,提升用户体验和数据展示的合理性。
* @param chatRoomDTO `ChatRoomDTO`Data Transfer Object
// `ChatRoomDTO` 一般用于在不同层之间传递查询参数,它会包含一些用于筛选群聊的属性,例如可以根据群聊名称、创建时间范围、群聊状态等条件来查询特定的群聊,
// 业务逻辑层可以根据具体的业务需求设置 `ChatRoomDTO` 的属性值,然后传递给该方法来获取符合条件的群聊数据。
* @return ChatRoomVO `Page<ChatRoomVO>` `ChatRoomVO`
// 这个返回结果可以方便地在业务逻辑层进一步处理,比如将分页数据传递给前端进行展示,或者根据业务需求对查询到的群聊数据进行二次加工等操作。
*/
Page<ChatRoomVO> queryChatRoom(Page<ChatRoomVO> page, @Param("chatRoomDTO") ChatRoomDTO chatRoomDTO);
/**
*
*
*
* @return
* @return `int`
// 方便后续基于数量进行相应的业务逻辑处理,比如判断是否达到某个数量阈值,进而决定是否需要进行一些资源调整或者提醒操作等。
*/
int countChatRoom();
/**
*
* `ExportChatRoomVO`
* `ExportChatRoomVO`
// 方便将这些数据按照一定的格式如Excel表格、CSV文件等进行导出以满足用户离线查看、数据分析或者数据备份等需求。
*
* @return ExportChatRoomVO
* @return ExportChatRoomVO `List<ExportChatRoomVO>` `ExportChatRoomVO`
// 列表中的每个元素代表一条需要导出的群聊记录对应的视图对象,在业务逻辑层可以进一步调用相关的导出工具或者方法,将这个列表数据转换为实际的文件进行导出操作。
*/
List<ExportChatRoomVO> exportChatRoom();
}
}

@ -5,17 +5,23 @@ import com.xcs.wx.domain.ContactHeadImg;
/**
* Mapper
* ContactHeadImgMyBatis PlusBaseMapper
* BaseMapperCRUD便
*
*
* @author xcs
* @date 202461815:33:26
* &#064;date 202461815:33:26
**/
public interface ContactHeadImgMapper extends BaseMapper<ContactHeadImg> {
/**
*
*
* ContactHeadImgContactHeadImg
* 便使
*
* @param usrName
* @return ContactHeadImg
* @param usrName
* @return ContactHeadImg ContactHeadImgnull
*/
ContactHeadImg getContactHeadImg(String usrName);
}
}

@ -4,10 +4,17 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xcs.wx.domain.ContactHeadImgUrl;
/**
* Mapper
*
* ContactHeadImgUrlMapperMyBatis Plus `BaseMapper`
* `BaseMapper`MyBatis Plus `insert``deleteById``selectById``updateById`
* 便
* @author xcs
* @date 20231221 1708
* &#064;date 20231221 1708
**/
public interface ContactHeadImgUrlMapper extends BaseMapper<ContactHeadImgUrl> {
}
// 由于该接口目前只是单纯地继承了BaseMapper接口没有自定义额外的方法所以暂时它仅具备BaseMapper<ContactHeadImgUrl>所提供的那些默认数据库操作功能。
// 但在后续业务拓展过程中,如果针对联系人头像数据有更复杂、特定的数据库操作需求(比如按照某些特定条件查询头像数据、关联查询其他相关表数据等),
// 就可以在这个接口中添加相应的自定义方法来满足业务要求,例如:
// public List<ContactHeadImgUrl> findHeadImgUrlsByUserName(String userName); // 假设根据用户名查找联系人头像相关信息的自定义方法示例
// 这样,业务逻辑层就能通过调用这个接口中定义的方法,方便地与数据库进行交互,实现对联系人头像数据的各种操作处理。
}

@ -4,10 +4,26 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xcs.wx.domain.ContactLabel;
/**
* Mapper
*
* ContactLabelMapperMyBatis Plus `BaseMapper`
* MyBatis Plus `BaseMapper` `insert``deleteById``selectById``updateById`
* `ContactLabelMapper` 便便SQL
* 使
*
* @author xcs
* @date 2023122217:19:20
* &#064;date 2023122217:19:20
*/
public interface ContactLabelMapper extends BaseMapper<ContactLabel> {
}
// 目前此接口仅继承了BaseMapper<ContactLabel>所以它暂时只具备BaseMapper所默认提供的针对ContactLabel实体类的数据库操作功能。
// 不过随着业务的发展和功能的拓展,如果后续对于联系人标签数据在数据库操作方面有了更复杂、更具针对性的需求,
// 比如按照标签名称模糊查询所有相关的联系人标签、统计每个联系人拥有的标签数量、批量删除某些标签等,
// 就可以在这个接口内添加相应的自定义方法来满足这些业务要求,示例如下:
// public List<ContactLabel> findContactLabelsByTagNameLike(String tagNameLike); // 根据标签名称模糊查询联系人标签的方法示例
// public int countLabelsByContactId(String contactId); // 统计指定联系人的标签数量的方法示例
// public int deleteLabelsByIds(List<String> labelIds); // 批量删除联系人标签的方法示例
// 通过在接口中添加这些自定义方法,业务逻辑层就能更加灵活、精准地与数据库交互,实现各种复杂多样的联系人标签相关业务逻辑的处理。
}

@ -13,47 +13,69 @@ import java.util.List;
import java.util.Set;
/**
* Mapper
*
* ContactMapperMyBatis Plus `BaseMapper`
* `BaseMapper`
* 便
* @author xcs
* @date 20231222 1351
* &#064;date 20231222 1351
**/
public interface ContactMapper extends BaseMapper<Contact> {
/**
*
* `ContactVO`
* `ContactVO` 使
* 使
*
* @param page
* @param contactDTO
* @return Contact
* @param page MyBatis Plus `Page`
// 如此一来,在查询数据库时就能按照设定好的分页规则准确获取相应的数据,方便在前端页面或者其他业务场景中进行分页展示联系人列表,提升用户体验与数据展示的合理性。
* @param contactDTO `ContactDTO`Data Transfer Object
// `ContactDTO` 通常用于在不同层之间传递查询参数,它包含了一系列用于筛选联系人的属性,比如可以按照联系人姓名、所属分组、添加时间范围等条件来查找特定的联系人,
// 业务逻辑层能够根据具体业务需求来设置 `ContactDTO` 的属性值,然后传递给该方法以获取符合条件的联系人数据。
* @return Contact `Page<ContactVO>` `ContactVO`
// 这个返回结果可在业务逻辑层进一步处理,例如将分页数据传递给前端进行展示,或者依据业务需求对查询到的联系人数据做二次加工等操作。
*/
Page<ContactVO> queryContact(Page<ContactVO> page, @Param("contactDTO") ContactDTO contactDTO);
/**
*
* `AllContactVO`
* `AllContactVO` 使便使
// 比如在联系人管理页面展示完整的联系人列表等情况,直接获取所有联系人数据进行展示,无需分页等额外操作。
*
* @return AllContactVO
* @return AllContactVO `List<AllContactVO>` `AllContactVO`
// 列表中的每个元素代表一条联系人记录对应的视图对象,业务逻辑层可对该列表数据进行进一步处理,如进行数据格式校验、传递给前端进行展示等操作。
*/
List<AllContactVO> queryAllContact();
/**
* Id
* IdId`Set``String`
// 在涉及区分联系人与公众号、对二者进行关联操作或者基于它们的Id进行其他业务逻辑处理如统计、权限判断等的场景中会用到这个方法获取相应的Id集合便于后续进一步操作。
*
* @return Contact
* @return Contact `Set<String>`Id
// 业务逻辑层可以根据业务需求对这个Id集合进行遍历、判断、与其他数据进行关联等操作以实现特定的业务功能。
*/
Set<String> getContactWithMp();
/**
*
*
*
* @return
* @return `int`
// 方便后续基于数量进行相应的业务逻辑处理,比如判断是否达到某个数量阈值,进而决定是否需要进行一些资源调整或者提醒操作等。
*/
int countContact();
/**
*
* `ExportContactVO`
* `ExportContactVO`
// 方便将这些数据按照一定的格式如Excel表格、CSV文件等进行导出操作以满足用户离线查看、数据分析或者数据备份等需求。
*
* @return ExportContactVO
* @return ExportContactVO `List<ExportContactVO>` `ExportContactVO`
// 列表中的每个元素代表一条需要导出的联系人记录对应的视图对象,业务逻辑层可进一步调用相关的导出工具或者方法,将这个列表数据转换为实际的文件进行导出操作。
*/
List<ExportContactVO> exportContact();
}
}

@ -4,11 +4,25 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xcs.wx.domain.FTSContactContent;
/**
* FTSContactContentMapper
*
* FTSContactContentMapper `FTSContactContent` MyBatis Plus `BaseMapper`
* MyBatis Plus `BaseMapper` `insert``deleteById``selectById``updateById`
* `BaseMapper``FTSContactContentMapper` 便 `FTSContactContent` SQL
* `FTSContactContent`
* `FTSContactContent`
* @author xcs
* @date 202461414:24:43
* &#064;date 202461414:24:43
**/
public interface FTSContactContentMapper extends BaseMapper<FTSContactContent> {
// 目前此接口仅单纯继承了BaseMapper<FTSContactContent>所以暂时它仅具备BaseMapper所默认提供的针对FTSContactContent实体类的数据库操作功能。
// 不过随着业务的拓展和功能需求的变化如果后续对于FTSContactContent数据在数据库操作方面有了更复杂、更具针对性的需求
// 例如按照特定内容字段进行模糊查询、关联查询其他相关表的数据、批量更新符合某些条件的记录等,
// 就可以在这个接口内添加相应的自定义方法来满足这些业务要求,示例如下:
// public List<FTSContactContent> findByContentLike(String contentLike); // 按照内容字段模糊查询的自定义方法示例
// public int updateBatchBySomeCondition(List<FTSContactContent> contentList, Map<String, Object> conditionMap); // 批量更新符合某些条件记录的自定义方法示例
}
// 通过在接口中添加这些自定义方法业务逻辑层就能更灵活、精准地与数据库交互实现各种复杂多样的与FTSContactContent相关的业务逻辑处理。
}

@ -5,9 +5,17 @@ import com.xcs.wx.domain.FTSRecentUsed;
/**
* 使 Mapper
* 使FTSRecentUsedMyBatis PlusBaseMapper
* BaseMapperinsertdeleteupdateselect
* 使便使
* 使使使
* Mapper使
*
* @author xcs
* @date 20231222 1351
* &#064;date 20231222 1351
**/
public interface FTSRecentUsedMapper extends BaseMapper<FTSRecentUsed> {
}
// 当前该接口只是单纯继承了BaseMapper并没有额外去自定义其他方法。
// 不过要是后续业务里出现了需要对最近使用关键字数据执行特殊数据库操作的情况,像按照用户分类统计不同用户常用的关键字、
// 或者查找长时间未使用的关键字进行清理等操作,便可以在这里添加相应的方法声明,接着在具体的实现类里去实现这些方法来满足业务逻辑的要求。
}

@ -5,10 +5,17 @@ import com.xcs.wx.domain.Feeds;
/**
* Mapper
* FeedsMyBatis PlusBaseMapper
* BaseMapperinsertdeleteupdateselect
* 便
*
* Mapper
*
* @author xcs
* @date 20231222 1351
* &#064;date 20231222 1351
**/
public interface FeedsMapper extends BaseMapper<Feeds> {
}
// 目前该接口仅继承了BaseMapper未自定义额外的方法。
// 如果后续业务中需要针对朋友圈相关的数据进行一些特殊的数据库操作,例如按照发布时间范围查询朋友圈动态、
// 根据用户关系筛选可见的朋友圈内容等,就可以在这里添加相应的方法声明,再去具体实现这些方法以满足业务逻辑的需求。
}

@ -6,17 +6,26 @@ import org.apache.ibatis.annotations.Param;
/**
* Mapper
* HardLinkImageAttributeMyBatis PlusBaseMapper
* BaseMapper使CRUD便
*
*
* @author xcs
* @date 202411621:50:13
* &#064;date 202411621:50:13
*/
public interface HardLinkImageAttributeMapper extends BaseMapper<HardLinkImageAttribute> {
/**
*
* MD5
* MD5byte[]
* String
* 便
*
* @param md5 md5
* MD5MD5MD5
* @return
* Stringnull
*/
String queryHardLinkImage(@Param("md5") byte[] md5);
}
}

@ -5,18 +5,24 @@ import com.xcs.wx.domain.HardLinkVideoAttribute;
import org.apache.ibatis.annotations.Param;
/**
* Mapper
*
* HardLinkVideoAttributeMapperMyBatis Plus `BaseMapper`
* `BaseMapper` 使
* 便
* @author xcs
* @date 202411621:50:13
* &#064;date 202411621:50:13
*/
public interface HardLinkVideoAttributeMapper extends BaseMapper<HardLinkVideoAttribute> {
/**
*
* MD5MD5
* MD5
*
* @param md5 md5
* @return
* @param md5 md5 `byte[]`MD5
// 这个MD5值应该是事先经过计算且能准确对应到数据库中存储的某个视频的标识信息确保能够准确地查找到目标视频相关的数据。
* @return `String`MD5
// 业务逻辑层接收到这个返回的字符串后,可以根据业务需求进一步对其进行解析、处理,比如将其用于构建视频播放地址、展示给用户等操作。
*/
String queryHardLinkVideo(@Param("md5") byte[] md5);
}
}

@ -5,49 +5,64 @@ import com.xcs.wx.domain.Msg;
import com.xcs.wx.domain.vo.CountRecentMsgsVO;
import com.xcs.wx.domain.vo.MsgTypeDistributionVO;
import com.xcs.wx.domain.vo.TopContactsVO;
import java.util.List;
/**
* Mapper
* MsgMyBatis PlusBaseMapper
* BaseMapperCRUD便
*
*
* @author xcs
* @date 20231222 1351
* &#064;date 20231222 1351
**/
public interface MsgMapper extends BaseMapper<Msg> {
/**
*
*
* MsgTypeDistributionVOMsgTypeDistributionVO便
*
*
* @return MsgTypeDistributionVO
* @return MsgTypeDistributionVO MsgTypeDistributionVO
*/
List<MsgTypeDistributionVO> msgTypeDistribution();
/**
* 15
* 15
* 15
* CountRecentMsgsVOCountRecentMsgsVO便
*
*
* @return MsgTrendVO
* @return CountRecentMsgsVO 15CountRecentMsgsVO
*/
List<CountRecentMsgsVO> countRecentMsgs();
/**
* 10
* 10
* TopContactsVOTopContactsVO
* 便
*
* @return MsgRankVO
* @return TopContactsVO 10TopContactsVO
*/
List<TopContactsVO> topContacts();
/**
*
*
*
*
* @return
* @return 0
*/
int countSent();
/**
*
*
* 便
*
* @return
* @return 0
*/
int countReceived();
}
}

@ -7,17 +7,27 @@ import com.xcs.wx.domain.vo.SessionVO;
import java.util.List;
/**
* Mapper
*
* SessionMapperMyBatis Plus `BaseMapper`
* `BaseMapper` `SessionMapper` 便 `Session`
* SQL
* 使
*
* @author xcs
* @date 20231221 1708
* &#064;date 20231221 1708
**/
public interface SessionMapper extends BaseMapper<Session> {
/**
*
*
* @return
* `SessionVO`
* `SessionVO` 使
* 使 `SessionVO`
* 便便
* @return `List<SessionVO>` `SessionVO`
// 业务逻辑层可以对这个返回的列表数据进行进一步处理,比如根据业务规则对会话进行排序、筛选,或者将其传递给前端页面进行展示等操作,以满足具体的业务需求。
*/
List<SessionVO> querySession();
}

@ -1,18 +1,20 @@
package com.xcs.wx.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xcs.wx.domain.Session;
import com.xcs.wx.domain.SqliteMaster;
import com.xcs.wx.domain.vo.SessionVO;
import java.util.List;
/**
* SQLite Mapper
* SQLite "sqlite_master" SqliteMasterMyBatis PlusBaseMapper
* BaseMapperCRUD便 "sqlite_master"
*
* Mapper "sqlite_master"
*
* @author xcs
* @date 20231221 1708
* &#064;date 20231221 1708
**/
public interface SqliteMasterMapper extends BaseMapper<SqliteMaster> {
// 目前该接口只是单纯继承了BaseMapper并没有额外去自定义其他方法。
// 不过要是后续业务里出现了需要对 "sqlite_master" 表数据执行特殊数据库操作的情况,像查找特定类型(如只查询表类型的记录)的系统表记录、
// 或者根据创建语句sql字段内容来筛选记录等操作便可以在这里添加相应的方法声明接着在具体的实现类里去实现这些方法来满足业务逻辑的要求。
}

@ -16,57 +16,74 @@ import java.util.stream.Collectors;
/**
* Mapping
* MapStruct便
* @Mapper(componentModel = "spring") Spring使Spring便
*
* @author xcs
* @date 20240108 1700
* &#064;date 20240108 1700
**/
@Mapper(componentModel = "spring")
public interface ChatRoomMapping {
/**
*
* ChatRoomMapStructChatRoomChatRoomVO
* chatRoomsChatRoomVOChatRoomVO使
*
* @param chatRooms
* @return ChatRoomVO
* @param chatRooms ChatRoomChatRoomIDChatRoom
* @return ChatRoomVO ChatRoomVOChatRoomVO
*/
List<ChatRoomVO> convert(List<ChatRoom> chatRooms);
/**
*
* ChatRoomChatRoomDetailVOMapStructChatRoomChatRoomDetailVO
* chatRoomChatRoomChatRoomDetailVOChatRoomDetailVO便使
*
* @param chatRoom
* @return ChatRoomDetailVO
* @param chatRoom ChatRoom
* @return ChatRoomDetailVO ChatRoomDetailVO
*/
ChatRoomDetailVO convert(ChatRoom chatRoom);
/**
*
* ChatRoomInfoChatRoomInfoVOMapStructChatRoomInfoChatRoomInfoVO
* ChatRoomInfo使ChatRoomInfoVO
*
* @param chatRoomInfo
* @return ChatRoomInfoVO
* @param chatRoomInfo ChatRoomInfoChatRoomInfo
* @return ChatRoomInfoVO ChatRoomInfoVO便使
*/
ChatRoomInfoVO convert(ChatRoomInfo chatRoomInfo);
/**
*
* ChatRoomProto.MemberChatRoomMemberVOMapStructChatRoomProto.MemberChatRoomMemberVO
* ChatRoomProto.MemberChatRoomMemberVOChatRoomMemberVO
*
* @param member
* @return ChatRoomMemberVO
* @param member ChatRoomProto.Member
* @return ChatRoomMemberVO ChatRoomMemberVO
*/
ChatRoomMemberVO convert(ChatRoomProto.Member member);
/**
*
* ChatRoomProto.MemberChatRoomMemberVOURL
* convertpeekURLIDURL
* peekIDChatRoomMemberVO
* 便使
*
* @param members
* @param headImgUrlMap
* @param contactNicknameMap
* @return ChatRoomMemberVO
* @param members ChatRoomProto.Member
* @param headImgUrlMap IDURL
* @param contactNicknameMap 使
* @return ChatRoomMemberVO ChatRoomMemberVOURL
*/
default List<ChatRoomMemberVO> convert(List<ChatRoomProto.Member> members, Map<String, String> headImgUrlMap, Map<String, String> contactNicknameMap) {
return members.stream()
// 对每个成员对象调用convert方法进行基本的类型转换将ChatRoomProto.Member类型转换为ChatRoomMemberVO类型
.map(this::convert)
// 使用peek操作对于每个转换后的成员对象设置其头像URL从headImgUrlMap中根据成员的微信ID获取对应的URL并设置
.peek(member -> member.setHeadImgUrl(headImgUrlMap.get(member.getWxId())))
// 再使用peek操作对于每个成员对象进行判断如果其群备注已经存在不为空字符串则不做处理直接返回如果不存在群备注则从contactNicknameMap中根据成员的微信ID获取对应的群昵称进行设置
.peek(member -> {
// 如果存在群备注则不处理
if (StrUtil.isNotBlank(member.getRemark())) {
@ -75,6 +92,7 @@ public interface ChatRoomMapping {
// 设置群昵称
member.setRemark(contactNicknameMap.get(member.getWxId()));
})
// 将处理后的成员对象收集为一个ChatRoomMemberVO类型对象的列表并返回
.collect(Collectors.toList());
}
}
}

@ -7,19 +7,30 @@ import org.mapstruct.Mapper;
import java.util.List;
/**
* Mapping
*
* ContactLabelMapping
* `ContactLabel` `ContactLabelVO`
* @author xcs
* @date 20231222 1500
* &#064;date 20231222 1500
**/
@Mapper(componentModel = "spring")
// @Mapper注解来自Mapstruct框架用于表明该接口是一个映射接口专门用于定义对象之间的转换规则。
// 而设置 `componentModel = "spring"` 这一属性表示生成的该接口对应的映射实现类将会以Spring组件的形式被管理起来。在Spring容器启动时会自动创建这个实现类的实例
// 方便在项目中其他需要进行对象转换的地方通过依赖注入的方式来使用从而使对象转换操作能够很好地融入到基于Spring的项目开发框架之中便于整体的项目开发与集成应用。
public interface ContactLabelMapping {
/**
*
*
* @param labels
* @return MsgDTO
* `ContactLabel` `ContactLabelVO`
* `ContactLabel` ID
* `ContactLabelVO`Value Object `ContactLabel` 使
* `ContactLabelVO` 便使
* @param labels `List<ContactLabel>` `ContactLabel`
// 这些 `ContactLabel` 对象通常是从数据库查询或者其他数据源获取而来,承载着联系人标签各方面的详细内容,是整个转换操作的数据源头,通过该参数传入相应的数据实例,以生成对应的 `ContactLabelVO` 列表数据。
* @return MsgDTO `List<ContactLabelVO>` `ContactLabelVO`
// 转换后的列表数据可以在业务逻辑层进一步处理,比如传递给服务层进行进一步的业务逻辑判断,或者直接返回给前端进行展示等操作,使得数据以更合适的形式参与到整个业务流程中。
*/
List<ContactLabelVO> convert(List<ContactLabel> labels);
}
}

@ -8,18 +8,23 @@ import java.util.List;
/**
* Mapping
* MapStructContact使ContactVO
* 便
* @Mapper(componentModel = "spring") Spring使Spring便
*
* @author xcs
* @date 20231222 1500
* &#064;date 20231222 1500
**/
@Mapper(componentModel = "spring")
public interface ContactMapping {
/**
*
* ContactMapStructContactContactVO
* entitiesContactVOContactVO使
*
* @param entities
* @return
* @param entities ContactContactIDContact
* @return ContactVOContactVO
*/
List<ContactVO> convert(List<Contact> entities);
}
}

@ -7,19 +7,30 @@ import org.mapstruct.Mapper;
import java.util.List;
/**
* Mapping
*
* FeedsMapping
* `Feeds` `FeedsVO` 使便
* @author xcs
* @date 20231221 1846
* &#064;date 20231221 1846
**/
@Mapper(componentModel = "spring")
// @Mapper注解来源于Mapstruct框架其作用是标识该接口为一个映射接口专门用于定义对象之间的转换规则。
// 通过设置 `componentModel = "spring"`意味着生成的映射实现类将会以Spring组件的形式进行管理。在Spring容器启动时会自动创建该接口对应的实现类实例
// 如此一来在项目中其他需要进行对象转换的地方就可以通过依赖注入的方式方便地使用该接口提供的转换功能让对象转换操作与整个基于Spring的项目架构无缝融合便于开发与应用集成。
public interface FeedsMapping {
/**
*
*
* @param feeds
* @return FeedsVO
* `Feeds` `FeedsVO`
* `Feeds` ID
* `FeedsVO`Value Object `Feeds` 使
* 便便使
* @param feeds `List<Feeds>` `Feeds` `Feeds`
// 它们承载着朋友圈动态各方面的详细内容,是需要进行转换的数据源头,通过该参数传入相应的数据实例,进而生成符合业务展示与使用需求的 `FeedsVO` 列表数据。
* @return FeedsVO `List<FeedsVO>` `FeedsVO`
// 转换后的列表数据可以在业务逻辑层进一步处理,比如传递给服务层用于组装响应数据返回给前端展示朋友圈动态列表,或者用于与其他系统进行数据交互等操作,确保数据以符合业务要求的形式参与到整个系统的运转当中。
*/
List<FeedsVO> convert(List<Feeds> feeds);
}
}

@ -7,29 +7,35 @@ import org.mapstruct.Mapper;
import java.util.List;
/**
* Mapping
* MapStruct
* @Mapper(componentModel = "spring")
* Spring使Spring便
*
* @author xcs
* @date 20231221 1846
* &#064;date 20231221 1846
**/
@Mapper(componentModel = "spring")
public interface MsgMapping {
/**
*
* MsgMapStructMsgMsgVO
* msgsMsgVOMsgVO
*
* @param msgs
* @return MsgDTO
* @param msgs MsgMsgMsg
* @return MsgDTO MsgVOMsgVO
*/
List<MsgVO> convert(List<Msg> msgs);
/**
*
* MsgVOExportMsgVOMapStructMsgVOExportMsgVO
* 使msgVOListMsgVOExportMsgVOExportMsgVO
*
* @param msgVOList
* @return ExportMsgVO
* @param msgVOList MsgVOMsgVO便MsgVO
* @return ExportMsgVO ExportMsgVOExportMsgVO使便
*/
List<ExportMsgVO> convertToExportMsgVO(List<MsgVO> msgVOList);
}
}

@ -5,19 +5,30 @@ import com.xcs.wx.domain.vo.RecoverContactVO;
import org.mapstruct.Mapper;
/**
* Mapping
*
* RecoverContactMapping
* `FTSContactContent` `RecoverContactVO` 使便
* @author xcs
* @date 202461415:57:18
* &#064;date 202461415:57:18
**/
@Mapper(componentModel = "spring")
// @Mapper注解来自Mapstruct框架用于表明该接口是一个专门用于定义对象转换规则的映射接口。
// 通过设置 `componentModel = "spring"`意味着生成的该接口对应的映射实现类将会以Spring组件的形式被管理起来。在Spring容器启动时会自动创建映射实现类的实例
// 这样在项目中其他需要进行这种数据转换的地方就可以通过依赖注入的方式便捷地使用该接口提供的转换功能使其能很好地融入基于Spring的项目架构中方便整体的开发与集成应用。
public interface RecoverContactMapping {
/**
*
*
* @param content
* @return RecoverContactVO
* `FTSContactContent` `RecoverContactVO`
* `FTSContactContent` 线
* `RecoverContactVO`Value Object `FTSContactContent` 使
* 便使
* @param content `FTSContactContent`
// 是整个转换操作的数据源头,其具体的属性内容依据业务中对 `FTSContactContent` 的定义而定,通过该参数传入具体的数据实例,以生成对应的 `RecoverContactVO` 数据结构,便于后续业务流程使用。
* @return RecoverContactVO `RecoverContactVO`使
// 转换后的对象可以在业务逻辑层进一步处理,比如传递给前端页面用于展示可能找回的联系人详情,或者供其他业务模块基于这些转换后的数据进行进一步的找回联系人相关的逻辑操作等,确保数据以合适的形式参与到整个业务流程之中。
*/
RecoverContactVO convert(FTSContactContent content);
}
}

@ -6,18 +6,23 @@ import org.mapstruct.Mapper;
/**
* Mapping
* MapStructSessionSessionVO
* SessionSessionVO便使
* @Mapper(componentModel = "spring") Spring使Spring便
*
* @author xcs
* @date 20231221 1846
* &#064;date 20231221 1846
**/
@Mapper(componentModel = "spring")
public interface SessionMapping {
/**
*
* SessionMapStructSessionVOSessionSession
* SessionVO使
*
* @param session
* @return SessionVO
* @param session Session
* @return SessionVO SessionVO
*/
SessionVO convert(Session session);
}
}

@ -5,19 +5,31 @@ import com.xcs.wx.domain.vo.UserInfoVO;
import org.mapstruct.Mapper;
/**
* Mapping
*
* UserMapping
* `UserBO`Business Object `UserInfoVO`Value Object
* 使使
* @author xcs
* @date 20231221 1846
* &#064;date 20231221 1846
**/
@Mapper(componentModel = "spring")
// @Mapper注解来自Mapstruct框架它的作用是标识这个接口为一个映射接口专门用于定义对象之间的转换规则。
// 同时设置 `componentModel = "spring"`表示生成的该接口对应的映射实现类将会以Spring组件的形式被管理起来。在Spring容器启动时会自动创建这个实现类的实例
// 这样一来在项目中其他需要进行用户数据转换的地方就可以通过依赖注入的方式方便地获取并使用该接口提供的转换功能使其能无缝融入基于Spring的项目架构便于整体的开发与集成应用。
public interface UserMapping {
/**
*
*
* @param userBO
* @return UserInfoVO
* `UserBO` `UserInfoVO`
* `UserBO`
* `UserInfoVO` `UserBO` 使
* 便便使
* @param userBO `UserBO`
// 是整个转换操作的数据源头,其具体的属性内容依据业务中对 `UserBO` 的定义而定,通过该参数传入相应的用户数据实例,进而生成符合业务展示与使用需求的 `UserInfoVO` 数据结构。
* @return UserInfoVO `UserInfoVO`使
// 转换后的对象可以在业务逻辑层进一步处理,比如传递给前端页面用于展示用户详细信息,或者供其他业务模块基于这些转换后的数据进行进一步的与用户相关的逻辑操作等,确保用户数据以合适的形式参与到整个业务流程之中。
*/
UserInfoVO convert(UserBO userBO);
}
}

@ -3,6 +3,9 @@ package com.xcs.wx.msg;
import com.xcs.wx.domain.vo.MsgVO;
/**
* MsgStrategy
* 使
* @author xcs
* @date 20240124 1144
**/
@ -10,17 +13,27 @@ public interface MsgStrategy {
/**
*
* typesubType
*
* trueprocess
*
* @param type
* @param subType
* @return
* @param type Integer
// 比如可能存在文本消息、图片消息等不同的大类每个大类会对应不同的type值以便区分开来进行不同的处理逻辑调用。
* @param subType Integer
// 例如在图片消息大类下可能还会根据图片来源、格式等再细分不同的子类型与type参数配合能精准定位到具体某一种消息从而准确判断是否适用当前的消息处理策略。
* @return booleantruefalse
// 该消息会按照其他相应的处理策略或者流程进行后续处理(如果存在的话),以此实现消息处理逻辑的分流和针对性调用。
*/
boolean support(Integer type, Integer subType);
/**
*
* `support` `MsgVO`
*
* 使便
*
* @param msgVO
* @param msgVO `MsgVO`
// 比如消息的原始内容、相关的附加信息等都可以通过 `MsgVO` 对象提供的方法进行访问,实现针对具体消息内容的针对性处理,使消息对象最终符合业务处理要求。
*/
void process(MsgVO msgVO);
}
}

@ -1,38 +1,47 @@
package com.xcs.wx.msg;
import cn.hutool.extra.spring.SpringUtil;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
/**
*
* typesubTypeMsgStrategy
*
* @author xcs
* @date 20240124 1555
**/
public class MsgStrategyFactory {
private MsgStrategyFactory(){}
// 将构造函数私有化防止外部通过new关键字创建该类的实例因为该类提供的功能主要通过静态方法来实现不需要外部直接实例化
private MsgStrategyFactory() {}
/**
*
* MsgStrategy
* SpringMsgStrategy便使
*
* @param type
* @param subType
* @return MsgStrategy
* @param type
* @param subType type
* @return MsgStrategy MsgStrategy
*/
public static MsgStrategy getStrategy(Integer type, Integer subType) {
// 从Spring中获取所有的策略
public static MsgStrategy getStrategy(Integer type, Integer subType) {
// 利用SpringUtil工具类从Spring容器中获取所有实现了MsgStrategy接口Bean即消息处理策略对象并以键值对的形式存放在一个Map中键为Bean的名称值为对应的MsgStrategy对象
Map<String, MsgStrategy> msgStrategyList = SpringUtil.getBeansOfType(MsgStrategy.class);
// 查找到的策略
// 创建一个AtomicReference对象用于存放查找到的符合条件的MsgStrategy对象AtomicReference是线程安全的适合在多线程环境下虽然此处不一定涉及多线程但使用它能保证代码的健壮性使用确保对其内部引用对象的操作不会出现并发问题。
AtomicReference<MsgStrategy> findMsgStrategy = new AtomicReference<>();
// 遍历
// 对获取到的所有消息处理策略对象进行遍历,逐一检查每个策略是否支持给定的消息类型和子类型
msgStrategyList.forEach((key, msgStrategy) -> {
// 查找是否支持该策略
// 调用每个MsgStrategy对象的support方法传入当前的消息类型和子类型参数判断该策略是否支持处理此类消息
// 如果支持即support方法返回true则将当前的MsgStrategy对象存入findMsgStrategy中意味着找到了合适的处理策略
if (msgStrategy.support(type, subType)) {
findMsgStrategy.set(msgStrategy);
}
});
// 返回
// 返回查找到的符合条件的消息处理策略对象如果没有找到合适的策略即findMsgStrategy.get()返回null则会返回null调用者需要进行相应的空值判断处理
return findMsgStrategy.get();
}
}
}

@ -11,34 +11,62 @@ import org.springframework.stereotype.Service;
/**
*
* MsgStrategy
* @Service Spring便Spring使
*
* @author xcs
* @date 20240124 1355
* &#064;date 20240124 1355
**/
@Service
public class AppletMsgStrategy implements MsgStrategy {
/**
*
* typesubType
* 493336truefalse
*
* @param type
* @param subType
* @return boolean type == 49 && (subType == 33 || subType == 36)truefalse
*/
@Override
public boolean support(Integer type, Integer subType) {
return type == 49 && (subType == 33 || subType == 36);
}
/**
*
* supportMsgVO
* XMLCompressContentBOWeAppInfoVOWeAppInfoVOMsgVO
* 便便使
*
* @param msgVO MsgVO
*/
@Override
public void process(MsgVO msgVO) {
// 使用Opt.ofNullable方法对msgVO.getCompressContent()进行包装,避免空指针异常,若压缩内容不为空,则执行后续操作
Opt.ofNullable(msgVO.getCompressContent())
// 若压缩内容不为空调用LZ4Util.decompress方法对消息的压缩内容进行解压操作将解压后的内容作为下一步操作的输入
.map(compressContent -> LZ4Util.decompress(msgVO.getCompressContent()))
// 对解压后的XML内容调用XmlUtil.parseXml方法按照CompressContentBO.class的定义将其解析为CompressContentBO对象用于后续提取小程序相关信息
.map(xmlContent -> XmlUtil.parseXml(xmlContent, CompressContentBO.class))
.ifPresent(msgBO -> Opt.ofNullable(msgBO.getAppMsg())
.ifPresent(appMsg -> {
// 创建一个WeAppInfoVO对象用于封装小程序相关信息
WeAppInfoVO weAppInfoVO = new WeAppInfoVO();
// 从解析后的CompressContentBO对象中的AppMsg部分获取标题信息并设置到weAppInfoVO对象中
weAppInfoVO.setTitle(msgBO.getAppMsg().getTitle());
// 从解析后的CompressContentBO对象中的AppMsg部分获取源显示名称信息并设置到weAppInfoVO对象中
weAppInfoVO.setSourceDisplayName(msgBO.getAppMsg().getSourceDisplayName());
// 将包含小程序相关信息的weAppInfoVO对象设置到msgVO对象中方便后续使用
msgVO.setWeAppInfo(weAppInfoVO);
CompressContentBO.AppMsg.WeAppInfo weAppInfo = appMsg.getWeAppInfo();
if (weAppInfo != null) {
if (weAppInfo!= null) {
// 如果小程序信息中的图标URL不为空将其设置到weAppInfoVO对象中
weAppInfoVO.setWeAppIconUrl(weAppInfo.getWeAppIconUrl());
// 如果小程序信息中的页面缩略图原始URL不为空将其设置到weAppInfoVO对象中
weAppInfoVO.setWeAppPageThumbRawUrl(weAppInfo.getWeAppPageThumbRawUrl());
}
}));
}
}
}

@ -10,32 +10,67 @@ import com.xcs.wx.util.XmlUtil;
import org.springframework.stereotype.Service;
/**
*
*
* CardLinkMsgStrategy `MsgStrategy`
* 便
* @author xcs
* @date 20240124 1356
* &#064;date 20240124 1356
**/
@Service
// @Service注解用于将该类标记为Spring框架中的一个服务层组件这样Spring容器在启动时会自动扫描并创建该类的实例将其纳入到容器的管理之中
// 方便在其他需要使用该服务的地方通过依赖注入的方式获取实例实现组件之间的解耦以及更灵活的调用使其能很好地融入基于Spring的项目架构中。
public class CardLinkMsgStrategy implements MsgStrategy {
/**
* supporttypesubType
*
*
* @param type Integer
* @param subType Integertype
* @return boolean type49subType5truefalse
*/
@Override
public boolean support(Integer type, Integer subType) {
return type == 49 && subType == 5;
}
/**
* process `MsgVO`
* XML便
*
* @param msgVO `MsgVO` `compressContent`
* 使便使
*/
@Override
public void process(MsgVO msgVO) {
// Opt.ofNullable方法来自于Hutool工具库的Opt类它用于对可能为null的对象进行包装处理避免空指针异常。
// 在这里它首先判断msgVO.getCompressContent()是否为null如果不为null则进行后续的链式操作否则整个链式操作直接短路不会执行后续步骤。
Opt.ofNullable(msgVO.getCompressContent())
// 如果msgVO.getCompressContent()不为null使用LZ4Util.decompress方法对消息的压缩内容进行解压操作
// LZ4Util应该是项目中自定义的一个工具类用于处理LZ4压缩算法相关的解压功能将解压后的内容传递给后续的链式操作。
.map(compressContent -> LZ4Util.decompress(msgVO.getCompressContent()))
// 对上一步解压后的内容xmlContent进行XML解析操作使用XmlUtil.parseXml方法将其解析为CompressContentBO类型的对象
// XmlUtil同样是项目中的自定义工具类用于处理XML解析相关的功能将解析后的对象传递给后续的链式操作方便后续提取其中的卡片式链接相关数据。
.map(xmlContent -> XmlUtil.parseXml(xmlContent, CompressContentBO.class))
// 如果前面的操作都成功执行也就是成功解析出了CompressContentBO对象那么通过ifPresent方法来执行后续的设置操作
// ifPresent方法会在传入的对象compressContentBO不为null时执行其内部的代码块在这里就是提取并设置卡片式链接相关的属性到对应的消息对象属性中。
.ifPresent(compressContentBO -> {
CardLinkVO cardLinkVO = new CardLinkVO();
// 从CompressContentBO对象中提取卡片式链接的标题信息并设置到新创建的CardLinkVO对象中
// 这里的CompressContentBO.getAppMsg().getTitle()表示从解析后的业务对象中获取应用消息AppMsg里包含的标题属性具体的对象结构和属性获取方式依据业务定义而定。
cardLinkVO.setTitle(compressContentBO.getAppMsg().getTitle());
// 提取卡片式链接的描述信息并设置到CardLinkVO对象中与设置标题的逻辑类似从CompressContentBO对象中获取相应的描述属性并赋值。
cardLinkVO.setDes(compressContentBO.getAppMsg().getDes());
// 提取卡片式链接的来源显示名称信息并设置到CardLinkVO对象中同样是从CompressContentBO对象中获取对应属性进行赋值操作。
cardLinkVO.setSourceDisplayName(compressContentBO.getAppMsg().getSourceDisplayName());
// 提取卡片式链接的链接地址信息并设置到CardLinkVO对象中确保CardLinkVO对象包含了完整的卡片式链接关键信息方便后续使用。
cardLinkVO.setUrl(compressContentBO.getAppMsg().getUrl());
// 将包含完整卡片式链接信息的CardLinkVO对象设置到传入的MsgVO消息对象中使得MsgVO对象能够持有并传递卡片式链接相关的数据便于在系统中其他地方使用该消息对象时获取这些信息。
msgVO.setCardLink(cardLinkVO);
// 设置MsgVO对象的文本内容strContent为固定的字符串"[卡片链接]",用于在某些展示场景下(比如消息列表展示简单内容时)能直观地表示该消息是卡片式链接消息类型,
// 具体的展示逻辑和使用场景依据业务需求而定。
msgVO.setStrContent("[卡片链接]");
});
}
}
}

@ -10,29 +10,53 @@ import org.springframework.stereotype.Service;
/**
*
* MsgStrategy
* @Slf4j Slf4j便使 @Service Spring使Spring
* 便
*
* @author xcs
* @date 20240124 1150
* &#064;date 20240124 1150
**/
@Slf4j
@Service
public class EmojiMsgStrategy implements MsgStrategy {
/**
*
* typesubType
* 470truefalse
*
* @param type
* @param subType
* @return boolean type == 47 && subType == 0truefalse
*/
@Override
public boolean support(Integer type, Integer subType) {
return type == 47 && subType == 0;
}
/**
*
* supportMsgVO
* strContentMsgBOMsgBOCDN
* MsgVO[]便
*
* @param msgVO MsgVO
*/
@Override
public void process(MsgVO msgVO) {
// 使用Opt.ofNullable方法对msgVO.getStrContent()进行包装,避免出现空指针异常,若消息文本内容不为空,则执行后续操作
Opt.ofNullable(msgVO.getStrContent())
// 若消息文本内容不为空调用XmlUtil.parseXml方法按照MsgBO.class的定义将文本内容解析为MsgBO对象用于后续提取表情相关信息
.map(xmlContent -> XmlUtil.parseXml(xmlContent, MsgBO.class))
.ifPresent(msgBO -> Opt.ofNullable(msgBO.getEmoji())
.map(MsgBO.Emoji::getCdnUrl)
.map(emojiUrl -> emojiUrl.replace("amp;", ""))
.ifPresent(emojiUrl -> {
// 将处理后的表情链接设置到msgVO对象的emojiUrl属性中方便后续获取和使用表情的链接信息
msgVO.setEmojiUrl(emojiUrl);
// 将msgVO对象的消息文本内容更新为固定的表示形式“[表情消息]”,使其在展示等场景下更符合表情消息的特征
msgVO.setStrContent("[表情消息]");
}));
}
}
}

@ -5,21 +5,41 @@ import com.xcs.wx.msg.MsgStrategy;
import org.springframework.stereotype.Service;
/**
*
*
* FileMsgStrategy `MsgStrategy`
* 便
* @author xcs
* @date 202461410:48:20
* &#064;date 202461410:48:20
**/
@Service
// @Service注解用于将该类标记为Spring框架中的一个服务层组件这样Spring容器在启动时会自动扫描并创建该类的实例把它纳入到容器的管理之中
// 方便在其他需要处理文件消息相关业务的地方通过依赖注入的方式获取实例实现组件之间的解耦以及更灵活的调用使其可以很好地融入基于Spring的项目架构里。
public class FileMsgStrategy implements MsgStrategy {
/**
* supporttypesubType
*
*
* @param type Integer
* @param subType Integertype
* @return boolean type49subType6truefalse
*/
@Override
public boolean support(Integer type, Integer subType) {
return type == 49 && subType == 6;
}
/**
* process `MsgVO`
* `strContent`"[文件]"便
* 使
*
* @param msgVO `MsgVO` `strContent`
* 使便
*/
@Override
public void process(MsgVO msgVO) {
msgVO.setStrContent("[文件]");
}
}
}

@ -2,43 +2,64 @@ package com.xcs.wx.msg.impl;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.ReUtil;
import com.xcs.wx.domain.bo.MsgBO;
import com.xcs.wx.domain.vo.MsgVO;
import com.xcs.wx.msg.MsgStrategy;
import com.xcs.wx.util.XmlUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
*
* MsgStrategy
* @Slf4j Slf4j便便使 @Service Spring使Spring
*
*
* @author xcs
* @date 20240124 1146
* &#064;date 20240124 1146
**/
@Slf4j
@Service
public class ImageMsgStrategy implements MsgStrategy {
/**
*
* typesubType
* 30truefalse
*
* @param type
* @param subType 便
* @return boolean type == 3 && subType == 0truefalse
*/
@Override
public boolean support(Integer type, Integer subType) {
return type == 3 && subType == 0;
}
/**
*
* supportbytesExtraMsgVO
* 便
*
* @param msgVO MsgVO
*/
@Override
public void process(MsgVO msgVO) {
// 使用Opt.ofNullable方法对msgVO.getBytesExtra()进行包装,避免出现空指针异常,若消息的额外字节信息不为空,则执行后续操作
Opt.ofNullable(msgVO.getBytesExtra())
// 若额外字节信息不为空,将字节数组转换为字符串形式,以便后续基于字符串内容进行正则匹配等操作来提取图片相关路径
.map(xmlContent -> new String(msgVO.getBytesExtra()))
.ifPresent(extra -> {
// 使用ReUtil工具类的getGroup0方法通过正则表达式匹配从extra字符串中提取图片的缩略图路径信息
// 正则表达式 "FileStorage\\\\MsgAttach\\\\[^\\\\]+\\\\Thumb\\\\[^\\\\]+\\\\[^\\\\]+\\.dat" 用于匹配符合特定格式的缩略图文件路径
String thumb = ReUtil.getGroup0("FileStorage\\\\MsgAttach\\\\[^\\\\]+\\\\Thumb\\\\[^\\\\]+\\\\[^\\\\]+\\.dat", extra);
// 同样使用ReUtil工具类的getGroup0方法通过另一个正则表达式匹配从extra字符串中提取图片的原始图像路径信息
// 正则表达式 "FileStorage\\\\MsgAttach\\\\[^\\\\]+\\\\Image\\\\[^\\\\]+\\\\[^\\\\]+\\.dat" 用于匹配符合特定格式的原始图像文件路径
String image = ReUtil.getGroup0("FileStorage\\\\MsgAttach\\\\[^\\\\]+\\\\Image\\\\[^\\\\]+\\\\[^\\\\]+\\.dat", extra);
// 将提取到的原始图像路径信息设置到msgVO对象的image属性中方便后续获取和使用图片的实际路径
msgVO.setImage(image);
// 将提取到的缩略图路径信息设置到msgVO对象的thumb属性中便于后续在需要展示缩略图等场景下使用
msgVO.setThumb(thumb);
// 将msgVO对象的消息文本内容更新为固定的表示形式“[图片]”,使其在展示等场景下更直观地体现是图片消息
msgVO.setStrContent("[图片]");
});
}
}
}

@ -5,21 +5,41 @@ import com.xcs.wx.msg.MsgStrategy;
import org.springframework.stereotype.Service;
/**
*
*
* MapMsgStrategy `MsgStrategy`
* 使
* @author xcs
* @date 20240124 1145
* &#064;date 20240124 1145
**/
@Service
// @Service注解用于将该类标记为Spring框架下的一个服务层组件这样一来在Spring容器启动时会自动扫描并创建该类的实例然后将其纳入到容器的管理范围之内
// 方便在其他需要处理地图消息相关业务的地方通过依赖注入的方式获取该实例以此实现组件之间的解耦让调用变得更加灵活确保该类能很好地融入基于Spring的项目架构之中便于整体的项目开发与集成应用。
public class MapMsgStrategy implements MsgStrategy {
/**
* supporttypesubType
*
*
* @param type Integer
* @param subType Integertype
* @return boolean type48subType0truefalse
*/
@Override
public boolean support(Integer type, Integer subType) {
return type == 48 && subType == 0;
}
/**
* process `MsgVO`
* `strContent`[]
* 便使
*
* @param msgVO `MsgVO` `strContent`
* 便
*/
@Override
public void process(MsgVO msgVO) {
msgVO.setStrContent("[地图消息]");
}
}
}

@ -12,33 +12,59 @@ import org.springframework.stereotype.Service;
/**
*
* MsgStrategy
* @Slf4j Slf4j便使 @Service Spring
* 使Spring便
*
* @author xcs
* @date 20240124 1353
* &#064;date 20240124 1353
**/
@Slf4j
@Service
public class ReferMsgStrategy implements MsgStrategy {
/**
*
* typesubType
* 4957truefalse
*
* @param type
* @param subType 便
* @return boolean type == 49 && subType == 57truefalse
*/
@Override
public boolean support(Integer type, Integer subType) {
return type == 49 && subType == 57;
}
/**
*
* supportMsgVO
* handleReferMsg便
*
* @param msgVO MsgVO
*/
@Override
public void process(MsgVO msgVO) {
// 使用Opt.ofNullable方法对msgVO.getCompressContent()进行包装,避免出现空指针异常,若消息的压缩内容不为空,则执行后续操作
Opt.ofNullable(msgVO.getCompressContent())
// 若压缩内容不为空调用LZ4Util.decompress方法对消息的压缩内容进行解压操作将解压后的内容作为下一步操作的输入
.map(compressContent -> LZ4Util.decompress(msgVO.getCompressContent()))
// 对解压后的内容调用XmlUtil.parseXml方法按照CompressContentBO.class的定义将其解析为CompressContentBO对象用于后续提取引用消息相关信息
.map(xmlContent -> XmlUtil.parseXml(xmlContent, CompressContentBO.class))
.ifPresent(compressContentBO -> msgVO.setStrContent(compressContentBO.getAppMsg().getTitle()))
// 调用handleReferMsg方法传入当前消息视图对象和解析得到的CompressContentBO对象进一步处理引用消息的详细内容
.ifPresent(compressContentBO -> handleReferMsg(msgVO, compressContentBO));
}
/**
*
*
* MsgVO便
* 便
*
* @param msgVO VO
* @param compressContentBO BO
* @param msgVO VOMsgVO
* @param compressContentBO BO
*/
private void handleReferMsg(MsgVO msgVO, CompressContentBO compressContentBO) {
Opt.ofNullable(compressContentBO)
@ -47,6 +73,7 @@ public class ReferMsgStrategy implements MsgStrategy {
.ifPresent(referMsg -> {
try {
String refContent;
// 根据引用消息内部所引用消息的类型进行不同的处理逻辑
if (referMsg.getType() == 49) {
refContent = Opt.ofNullable(referMsg.getContent())
.map(content -> XmlUtil.parseXml(referMsg.getContent(), CompressContentBO.class))
@ -64,13 +91,16 @@ public class ReferMsgStrategy implements MsgStrategy {
} else {
refContent = referMsg.getContent();
}
// 如果处理后的引用内容为空字符串,将其设置为默认值 "None"
if (StrUtil.isEmpty(refContent)) {
refContent = "None";
}
// 将处理后的引用消息内容设置到msgVO对象的referMsgContent属性中格式为引用消息的显示名称加上具体内容并去除可能存在的特殊字符这里是 "<22>"
msgVO.setReferMsgContent(referMsg.getDisplayName() + "" + refContent.replace("<22>", ""));
} catch (Exception e) {
log.error("handle refer msg fail" ,e);
// 如果在处理引用消息过程中出现异常,使用日志框架记录错误信息,方便后续排查处理引用消息失败的原因
log.error("handle refer msg fail", e);
}
});
}
}
}

@ -8,37 +8,78 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
*
*
* SystemMsgStrategy `MsgStrategy`
* 使使
* @author xcs
* @date 20240124 1354
* &#064;date 20240124 1354
**/
@Service
// @Service注解用于将该类标记为Spring框架中的一个服务层组件这样Spring容器在启动时会自动扫描并创建该类的实例将其纳入到容器的管理之中
// 方便在其他需要处理系统消息相关业务的地方通过依赖注入的方式获取实例实现组件之间的解耦以及更灵活的调用使其能很好地融入基于Spring的项目架构中。
public class SystemMsgStrategy implements MsgStrategy {
// 定义一个静态的正则表达式字符串,用于匹配系统消息中特定的内容格式。
// 这个正则表达式的含义是:匹配以 <img src="SystemMessages_HongbaoIcon.png"/> 开头,接着是任意字符(由.+ 表示),最后以 </_wc_custom_link_> 结尾的字符串模式。
// 其目的可能是从系统消息的文本内容中提取出符合该模式的关键信息部分,具体的提取逻辑会在后续代码中使用该正则表达式进行处理时体现出来。
private static final String REGEX = "<img src=\"SystemMessages_HongbaoIcon.png\"/>(.+)</_wc_custom_link_>";
/**
* supporttypesubType
*
*
* @param type Integer
* @param subType Integertype
* @return boolean type10000subType0truefalse
*/
@Override
public boolean support(Integer type, Integer subType) {
return type == 10000 && subType == 0;
}
/**
* process `MsgVO`
* 使HTML便
*
* @param msgVO `MsgVO` `strContent`
* 使便使
*/
@Override
public void process(MsgVO msgVO) {
// 替换内容
// 这里使用replaceAll方法对消息对象的strContent属性即消息的文本内容进行处理将其中的 "<revokemsg>" 和 "</revokemsg>" 标签全部替换为空字符串,
// 目的可能是去除消息内容中与撤回消息相关的标记或者不需要展示的特定标签内容,使得消息文本更加简洁、符合实际展示需求。
msgVO.setStrContent(msgVO.getStrContent().replaceAll("<revokemsg>|</revokemsg>", ""));
// 使用正则表达式匹配需要的内容
// 创建一个Pattern对象通过调用Pattern.compile方法并传入预定义的正则表达式REGEX来进行编译得到一个用于正则匹配的模式对象
// 后续就可以利用这个模式对象去对消息文本内容进行匹配操作,查找符合该正则表达式模式的部分内容。
Pattern pattern = Pattern.compile(REGEX);
// 对StrContent进行匹配
// 使用上一步创建的Pattern对象的matcher方法传入消息对象的strContent属性即要匹配的文本内容创建一个Matcher对象
// 这个Matcher对象提供了一系列方法用于在文本中查找、匹配符合给定正则表达式模式的内容接下来就可以通过它来进行具体的匹配操作了。
Matcher matcher = pattern.matcher(msgVO.getStrContent());
// 匹配成功
// 通过调用Matcher对象的find方法来尝试在消息文本内容中查找是否存在符合正则表达式模式的部分
// 如果找到了匹配的内容find方法会返回true然后就可以进行后续提取匹配文本等操作如果没找到匹配内容则返回false跳过后续提取等操作。
if (matcher.find()) {
// 提取匹配的文本
// 当匹配成功后使用matcher.group(1)方法提取出符合正则表达式中第一个括号捕获组(即.+ 部分所匹配的内容)的文本,
// 并通过trim方法去除文本前后可能存在的空白字符得到相对纯净的匹配文本内容以便后续进一步处理和使用。
String extractedText = matcher.group(1).trim();
// 进一步处理以去除内部的HTML标签
// 使用replaceAll方法配合HTML标签的正则表达式模式 "<[^>]+>"将提取出来的文本中所有的HTML标签如 <div>、<span> 等)都替换为空字符串,
// 再次通过trim方法去除处理后文本前后可能出现的空白字符使得最终得到的文本内容更加纯净只保留了实际需要展示的文本信息去除了不必要的HTML格式标签。
extractedText = extractedText.replaceAll("<[^>]+>", "").trim();
// 设置消息内容
// 将经过上述处理后得到的纯净文本内容设置回消息对象的strContent属性中这样消息对象的文本内容就更新为处理后的合适内容了
// 方便后续在系统中进行展示(比如在消息列表展示消息详情时呈现更清晰的系统消息文本)或者其他业务逻辑处理(如根据消息内容进行相关判断等)。
msgVO.setStrContent(extractedText);
}
}
}
}

@ -6,6 +6,9 @@ import org.springframework.stereotype.Service;
/**
*
* MsgStrategy
* `process`
* @Service Spring使Spring便
*
* @author xcs
* @date 20240124 1145
@ -13,13 +16,32 @@ import org.springframework.stereotype.Service;
@Service
public class TextMsgStrategy implements MsgStrategy {
/**
*
* typesubType
* 10truefalse
*
* @param type
* @param subType
* @return boolean type == 1 && subType == 0truefalse
*/
@Override
public boolean support(Integer type, Integer subType) {
return type == 1 && subType == 0;
}
/**
*
* support
* 便便使
*
* @param msgVO MsgVO
*/
@Override
public void process(MsgVO msgVO) {
// 此处暂时为空实现,后续可根据业务需求添加对文本消息的具体处理逻辑,比如:
// 1. 可以对msgVO中的文本内容进行格式校验、清洗等操作例如去除多余的空格、特殊字符等。
// 2. 提取文本消息中的关键信息,如提取特定关键词用于统计分析等。
// 3. 根据文本消息内容记录相关日志,便于后续排查问题或者进行业务监控等操作。
}
}
}

@ -5,21 +5,41 @@ import com.xcs.wx.msg.MsgStrategy;
import org.springframework.stereotype.Service;
/**
*
*
* VideoMsgStrategy `MsgStrategy`
* 便
* @author xcs
* @date 20240124 1352
**/
@Service
// @Service注解用于将该类标记为Spring框架下的一个服务层组件这样一来在Spring容器启动时会自动扫描并创建该类的实例然后将其纳入到容器的管理范围之内
// 方便在其他需要处理视频消息相关业务的地方通过依赖注入的方式获取该实例以此实现组件之间的解耦让调用变得更加灵活确保该类能很好地融入基于Spring的项目架构之中便于整体的项目开发与集成应用。
public class VideoMsgStrategy implements MsgStrategy {
/**
* supporttypesubType
*
*
* @param type Integer
* @param subType Integertype
* @return boolean type34subType0truefalse
*/
@Override
public boolean support(Integer type, Integer subType) {
return type == 34 && subType == 0;
}
/**
* process `MsgVO`
* `strContent`[]
* 便使
*
* @param msgVO `MsgVO` `strContent`
* 便
*/
@Override
public void process(MsgVO msgVO) {
msgVO.setStrContent("[视频]");
}
}
}

@ -6,6 +6,8 @@ import org.springframework.stereotype.Service;
/**
*
* MsgStrategy
* @Service Spring使Spring便
*
* @author xcs
* @date 20240124 1351
@ -13,13 +15,30 @@ import org.springframework.stereotype.Service;
@Service
public class VoiceMsgStrategy implements MsgStrategy {
/**
*
* typesubType
* 430truefalse
*
* @param type
* @param subType 便
* @return boolean type == 43 && subType == 0truefalse
*/
@Override
public boolean support(Integer type, Integer subType) {
return type == 43 && subType == 0;
}
/**
*
* supportMsgVOstrContent[]
* 便
*
* @param msgVO MsgVO
*/
@Override
public void process(MsgVO msgVO) {
// 将msgVO对象的strContent属性设置为"[语音]",用于在展示等业务场景中表明该消息是语音消息类型
msgVO.setStrContent("[语音]");
}
}
}

@ -8,23 +8,49 @@ import com.xcs.wx.util.XmlUtil;
import org.springframework.stereotype.Service;
/**
*
*
* VoipMsgStrategy `MsgStrategy`
* 使
* @author xcs
* @date 20240124 1400
**/
@Service
// @Service注解用于将该类标记为Spring框架中的一个服务层组件这样Spring容器在启动时会自动扫描并创建该类的实例将其纳入到容器的管理之中
// 方便在其他需要处理语音电话消息相关业务的地方通过依赖注入的方式获取实例实现组件之间的解耦以及更灵活的调用使其能很好地融入基于Spring的项目架构中。
public class VoipMsgStrategy implements MsgStrategy {
/**
* supporttypesubType
*
*
* @param type Integer
* @param subType Integertype
* @return boolean type50subType0truefalse
*/
@Override
public boolean support(Integer type, Integer subType) {
return type == 50 && subType == 0;
}
/**
* process `MsgVO`
* `strContent`XML `VoipMsgBO` `strContent` 便
*
* @param msgVO `MsgVO` `strContent`
* 使便使
*/
@Override
public void process(MsgVO msgVO) {
// Opt.ofNullable方法来自Hutool工具库它用于对可能为null的对象进行包装处理避免出现空指针异常。
// 在这里它对msgVO.getStrContent()进行判断如果该值不为null则进行后续的链式操作若为null则整个链式操作直接短路不会执行后续步骤。
Opt.ofNullable(msgVO.getStrContent())
// 如果msgVO.getStrContent()不为null使用XmlUtil.parseXml方法对其进行XML解析操作将解析后的内容转换为VoipMsgBO类型的对象。
// XmlUtil是项目中自定义的工具类用于处理XML解析相关的功能通过传入的xmlContent即msgVO.getStrContent()的值和指定的目标类型VoipMsgBO.class
// 尝试将XML内容解析为对应的Java对象方便后续提取其中的语音电话消息相关数据。
.map(xmlContent -> XmlUtil.parseXml(xmlContent, VoipMsgBO.class))
// 如果前面的XML解析操作成功也就是成功得到了VoipMsgBO对象那么通过ifPresent方法来执行后续的设置操作。
// ifPresent方法会在传入的对象voipMsgBO不为null时执行其内部的代码块在这里就是从VoipMsgBO对象中提取关键的消息内容并设置到msgVO对象的strContent属性中。
.ifPresent(voipMsgBO -> msgVO.setStrContent(voipMsgBO.getVoIPBubbleMsg().getMsg()));
}
}
}

@ -3,25 +3,38 @@ spring:
druid:
stat-view-servlet:
enabled: true
# 启用 Druid 数据源的监控页面相关的 Servlet设置为 true 表示开启该功能这样可以通过访问对应的页面来查看数据源的监控信息比如连接数、SQL 执行情况等。
login-username: admin
# 设置访问 Druid 监控页面的登录用户名,这里设置为 "admin",用于权限验证,确保只有授权用户可以查看监控数据。
login-password: 123456
# 设置访问 Druid 监控页面的登录密码,为 "123456",与用户名配合进行身份认证。
dynamic:
druid:
initial-size: 5
# 设置 Druid 连接池初始化时创建的连接数量为 5 个,即项目启动时就会预先创建好这么多数据库连接,方便后续使用,避免频繁创建连接带来的性能开销。
max-active: 8
# 定义连接池中最大的活动连接数为 8 个,也就是同时最多可以有 8 个数据库连接处于使用状态,超过这个数量后续请求获取连接时可能需要等待。
min-idle: 3
# 设置连接池中最小的空闲连接数为 3 个,当空闲连接数低于这个值时,连接池可能会自动创建新的连接补充,以保证有足够的空闲连接可用于后续请求。
max-wait: 1000
# 设置获取连接时的最大等待时间为 1000 毫秒1 秒),如果在这个时间内无法获取到可用连接,可能会抛出相应的异常,避免长时间等待导致系统性能问题。
test-while-idle: false
# 设置为 false 表示在连接空闲时不进行有效性检测,通常在一些场景下,如果不需要频繁检测空闲连接是否可用,可以设置为 false 来减少性能开销;若设置为 true则会按一定规则检测空闲连接能否正常使用。
wechat-offset:
version:
"[3.9.8.25]":
nickname: 65000920
# 针对版本号为 "3.9.8.25" 的配置项,设置昵称对应的数值为 65000920具体该数值代表的实际含义需结合业务场景来确定可能是某种内部编码或者特定的业务标识等。
account: 65002256
# 设置账号对应的数值为 65002256同样其具体意义取决于具体的业务逻辑可能与微信账号相关的某种映射或者配置有关。
mobile: 65000728
# 设置手机号对应的数值为 65000728也许是在业务处理中对手机号进行了特定的编码或者关联了其他相关属性这里通过配置文件进行统一管理。
"[3.9.9.27]":
nickname: 68065304
account: 68065080
mobile: 68065112
# 以下各版本号下的配置项同理,都是针对不同版本分别设置昵称、账号、手机号对应的数值,方便根据不同的微信版本进行差异化的业务处理和数据关联。
"[3.9.9.35]":
nickname: 68065304
account: 68065080
@ -66,15 +79,23 @@ wechat-offset:
nickname: 93834984
account: 93834760
mobile: 93834792
mybatis-plus:
global-config:
banner: off
# 将 MyBatis Plus 的启动 banner启动时显示的 logo 和相关信息)关闭,设置为 "off" 表示不显示,在一些生产环境或者不需要展示该信息的场景下可以进行这样的设置,避免输出过多不必要的信息。
#configuration:
#log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启sql日志
# 这部分被注释掉了,如果取消注释,通过指定 "log-impl" 为 "org.apache.ibatis.logging.stdout.StdOutImpl",则可以开启 MyBatis Plus 的 SQL 日志功能,
# 这样在项目运行时会将执行的 SQL 语句打印到控制台,方便调试和查看数据库操作情况,但在生产环境一般不建议开启,以免产生大量日志影响性能和占用过多存储空间。
logging:
level:
root: INFO
# 设置项目日志的根级别为 INFO意味着 INFO 级别及以上(如 WARN、ERROR 等)的日志消息会被输出,用于记录项目整体运行过程中的一般性信息,方便查看项目运行状态。
com.alibaba.druid.pool.DruidDataSource: WARN
# 将阿里巴巴 Druid 数据源连接池相关的日志级别设置为 WARN即只有 WARN 级别及以上的关于 Druid 数据源的日志消息才会被输出,避免输出过多的连接池相关的低级别日志信息,减少日志量。
com.baomidou.dynamic.datasource.DynamicRoutingDataSource: WARN
# 针对 MyBatis Plus 的动态数据源相关模块DynamicRoutingDataSource设置日志级别为 WARN同样是为了控制该部分产生的日志数量只输出重要的警告及以上级别的日志。
com.baomidou.dynamic.datasource.destroyer.DefaultDataSourceDestroyer: WARN
# 对 MyBatis Plus 的默认数据源销毁器DefaultDataSourceDestroyer模块设置日志级别为 WARN控制该模块输出的日志内容聚焦在重要的警告等情况的记录上。

@ -1,12 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 这个 mapper 标签定义了 MyBatis 的映射器namespace 属性指定了该映射器对应的接口全限定名,
通过这个对应关系MyBatis 能将接口方法与下面定义的 SQL 语句进行关联 -->
<mapper namespace="com.xcs.wx.mapper.ChatRoomMapper">
<!-- 定义了名为 "chatRoomResultMap" 的结果映射,用于将查询结果映射到 com.xcs.wx.domain.vo.ChatRoomVO 类型的对象上 -->
<resultMap id="chatRoomResultMap" type="com.xcs.wx.domain.vo.ChatRoomVO">
<!-- 将查询结果中的 "chatRoomName" 列的值映射到 ChatRoomVO 对象的 chatRoomName 属性上 -->
<result property="chatRoomName" column="chatRoomName" />
<result property="isShowName" column="isShowName" />
<result property="selfDisplayName" column="selfDisplayName" />
<!-- 将 "roomData" 列的值映射到 ChatRoomVO 对象的 roomData 属性上,并指定了类型处理器为 ByteArrayTypeHandler
用于处理字节数组类型的数据转换 -->
<result property="roomData" column="roomData" typeHandler="org.apache.ibatis.type.ByteArrayTypeHandler"/>
<result property="chatRoomTitle" column="chatRoomTitle" />
<result property="createBy" column="createBy" />
@ -15,6 +21,7 @@
<result property="dissolution" column="dissolution" />
</resultMap>
<!-- 定义了名为 "exportChatRoomResultMap" 的结果映射,用于将查询结果映射到 com.xcs.wx.domain.vo.ExportChatRoomVO 类型的对象上 -->
<resultMap id="exportChatRoomResultMap" type="com.xcs.wx.domain.vo.ExportChatRoomVO">
<result property="chatRoomName" column="chatRoomName" />
<result property="selfDisplayName" column="selfDisplayName" />
@ -25,47 +32,54 @@
<result property="dissolution" column="dissolution" />
</resultMap>
<!-- 查询群聊 -->
<!-- 以下是名为 "queryChatRoom" 的查询语句配置,使用 "chatRoomResultMap" 结果映射来处理查询结果,
参数类型为 com.xcs.wx.domain.dto.ChatRoomDTO用于根据条件查询群聊相关信息 -->
<select id="queryChatRoom" resultMap="chatRoomResultMap" parameterType="com.xcs.wx.domain.dto.ChatRoomDTO">
<!-- 具体的 SQL 查询语句,从多个表中查询群聊相关信息,包括群聊名称、是否显示名称、自定义显示名称、群聊数据等 -->
SELECT
cr.ChatRoomName as chatRoomName,
cr.IsShowName as isShowName,
cr.SelfDisplayName as selfDisplayName,
cr.RoomData as roomData,
c.NickName as chatRoomTitle,
c1.NickName as createBy,
chiu.smallHeadImgUrl as headImgUrl,
CASE WHEN cr.Reserved2 LIKE '%@openim' THEN 1 ELSE 0 END as enterprise,
CASE WHEN cr.Reserved2 = '' THEN 1 ELSE 0 END as dissolution
cr.ChatRoomName as chatRoomName,
cr.IsShowName as isShowName,
cr.SelfDisplayName as selfDisplayName,
cr.RoomData as roomData,
c.NickName as chatRoomTitle,
c1.NickName as createBy,
chiu.smallHeadImgUrl as headImgUrl,
CASE WHEN cr.Reserved2 LIKE '%@openim' THEN 1 ELSE 0 END as enterprise,
CASE WHEN cr.Reserved2 = '' THEN 1 ELSE 0 END as dissolution
FROM
ChatRoom cr
LEFT JOIN Contact c ON cr.ChatRoomName = c.UserName
LEFT JOIN Contact c1 ON cr.Reserved2 = c1.UserName
LEFT JOIN ContactHeadImgUrl chiu ON cr.ChatRoomName = chiu.usrName
ChatRoom cr
LEFT JOIN Contact c ON cr.ChatRoomName = c.UserName
LEFT JOIN Contact c1 ON cr.Reserved2 = c1.UserName
LEFT JOIN ContactHeadImgUrl chiu ON cr.ChatRoomName = chiu.usrName
WHERE
cr.ChatRoomName != ''
<if test="chatRoomDTO.chatRoomTitle != null and chatRoomDTO.chatRoomTitle != ''">
cr.ChatRoomName!= ''
<!-- 以下是动态 SQL 条件判断,如果传入的 ChatRoomDTO 对象中的 chatRoomTitle 属性不为空且不为空字符串,
则添加相应的模糊查询条件 -->
<if test="chatRoomDTO.chatRoomTitle!= null and chatRoomDTO.chatRoomTitle!= ''">
AND c.NickName like '%' || #{chatRoomDTO.chatRoomTitle} || '%'
</if>
<if test="chatRoomDTO.selfDisplayName != null and chatRoomDTO.selfDisplayName != ''">
<!-- 同理,以下条件判断用于根据传入的 ChatRoomDTO 对象中的 selfDisplayName 属性添加模糊查询条件 -->
<if test="chatRoomDTO.selfDisplayName!= null and chatRoomDTO.selfDisplayName!= ''">
AND cr.SelfDisplayName like '%' || #{chatRoomDTO.selfDisplayName} || '%'
</if>
<if test="chatRoomDTO.createBy != null and chatRoomDTO.createBy != ''">
<!-- 根据传入的 ChatRoomDTO 对象中的 createBy 属性添加模糊查询条件 -->
<if test="chatRoomDTO.createBy!= null and chatRoomDTO.createBy!= ''">
AND c1.NickName like '%' || #{chatRoomDTO.createBy} || '%'
</if>
</select>
<!-- 统计群聊数量 -->
<!-- 名为 "countChatRoom" 的查询语句配置,用于统计群聊数量,返回结果类型为 java.lang.Integer -->
<select id="countChatRoom" resultType="java.lang.Integer">
SELECT
COUNT(*)
FROM
ChatRoom
WHERE
ChatRoomName != ''
ChatRoomName!= ''
</select>
<!-- 导出群聊 -->
<!-- 名为 "exportChatRoom" 的查询语句配置,使用 "exportChatRoomResultMap" 结果映射来处理查询结果,
用于导出群聊相关信息 -->
<select id="exportChatRoom" resultMap="exportChatRoomResultMap">
SELECT
cr.ChatRoomName as chatRoomName,
@ -77,10 +91,10 @@
CASE WHEN cr.Reserved2 = '' THEN 1 ELSE 0 END as dissolution
FROM
ChatRoom cr
LEFT JOIN Contact c ON cr.ChatRoomName = c.UserName
LEFT JOIN Contact c1 ON cr.Reserved2 = c1.UserName
LEFT JOIN Contact c ON cr.ChatRoomName = c.UserName
LEFT JOIN Contact c1 ON cr.Reserved2 = c1.UserName
WHERE
cr.ChatRoomName != ''
cr.ChatRoomName!= ''
</select>
</mapper>
</mapper>

@ -1,17 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 这里定义了一个 MyBatis 的映射器mappernamespace 属性指定了该映射器对应的接口全限定名,
通过这个对应关系MyBatis 可以将接口中的方法与下面定义的 SQL 语句进行关联操作 -->
<mapper namespace="com.xcs.wx.mapper.ContactHeadImgMapper">
<!-- 定义了名为 "contactHeadImgMap" 的结果映射resultMap它用于将查询结果中的数据映射到 com.xcs.wx.domain.ContactHeadImg 类型的 Java 对象上 -->
<resultMap id="contactHeadImgMap" type="com.xcs.wx.domain.ContactHeadImg">
<!-- 将查询结果里名为 "usrName" 的列的值,映射到 ContactHeadImg 类对象的 usrName 属性上 -->
<result property="usrName" column="usrName" />
<!-- 将名为 "createTime" 的列的值,映射到 ContactHeadImg 类对象的 createTime 属性上 -->
<result property="createTime" column="createTime" />
<!-- 将名为 "smallHeadBuf" 的列的值,映射到 ContactHeadImg 类对象的 smallHeadBuf 属性上,
并且指定了类型处理器typeHandler为 org.apache.ibatis.type.ByteArrayTypeHandler用于处理字节数组类型的数据转换 -->
<result property="smallHeadBuf" column="smallHeadBuf" typeHandler="org.apache.ibatis.type.ByteArrayTypeHandler"/>
<!-- 将名为 "m_headImgMD5" 的列的值(这里列名与属性名不完全一致,注意对应关系),映射到 ContactHeadImg 类对象的 headImgMd5 属性上 -->
<result property="headImgMd5" column="m_headImgMD5" />
</resultMap>
<!-- 定义了一个名为 "getContactHeadImg" 的查询语句配置,它使用前面定义的 "contactHeadImgMap" 结果映射来处理查询结果,
参数类型parameterType为 String表示传入的参数是一个字符串类型用于根据用户名usrName查询联系人头像相关信息 -->
<select id="getContactHeadImg" resultMap="contactHeadImgMap" parameterType="String">
<!-- 具体的 SQL 查询语句,从名为 ContactHeadImg1 的表中查询指定用户名usrName对应的联系人头像相关记录这里使用了占位符 #{usrName}
MyBatis 会在执行时将传入的参数值替换到这个位置 -->
SELECT * FROM ContactHeadImg1 where usrName = #{usrName}
</select>
</mapper>
</mapper>

@ -1,41 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 定义 MyBatis 的映射器namespace 属性指定了该映射器对应的接口全限定名,
通过这个对应关系MyBatis 能将接口方法与下面定义的 SQL 语句进行关联操作 -->
<mapper namespace="com.xcs.wx.mapper.ContactMapper">
<!-- 查询联系人 -->
<!-- 名为 "queryContact" 的查询语句配置,用于根据特定条件查询联系人信息,
返回结果类型为 com.xcs.wx.domain.vo.ContactVO参数类型是 com.xcs.wx.domain.dto.ContactDTO
意味着可以根据传入的 ContactDTO 对象中的条件来筛选查询结果 -->
<select id="queryContact" resultType="com.xcs.wx.domain.vo.ContactVO" parameterType="com.xcs.wx.domain.dto.ContactDTO">
<!-- 具体的 SQL 查询语句,从 Contact 表和 ContactHeadImgUrl 表中查询联系人相关信息,
包括用户名、别名、备注、昵称、标签列表、描述以及头像链接等 -->
SELECT
c.UserName as userName,
CASE WHEN c.Alias IS NULL OR c.Alias = '' THEN c.UserName ELSE c.Alias END AS alias,
c.Remark as remark,
c.NickName as nickName,
c.LabelIDList as labelIdList,
c.Reserved6 as describe,
chiu.smallHeadImgUrl as headImgUrl
c.UserName as userName,
CASE WHEN c.Alias IS NULL OR c.Alias = '' THEN c.UserName ELSE c.Alias END AS alias,
c.Remark as remark,
c.NickName as nickName,
c.LabelIDList as labelIdList,
c.Reserved6 as describe,
chiu.smallHeadImgUrl as headImgUrl
FROM
Contact c LEFT JOIN ContactHeadImgUrl chiu ON c.UserName=chiu.usrName
Contact c LEFT JOIN ContactHeadImgUrl chiu ON c.UserName=chiu.usrName
WHERE
Type % 2 = 1
AND VerifyFlag = 0
AND UserName NOT IN ( 'floatbottle', 'fmessage', 'medianote','filehelper' )
AND UserName NOT LIKE '%@chatroom'
<if test="contactDTO.remark != null and contactDTO.remark != ''">
<!-- 筛选条件,只选择 Type 字段值除以 2 余数为 1 的记录,同时 VerifyFlag 为 0
并且排除一些特定的用户名,还排除用户名类似以 '%@chatroom' 结尾的聊天群组相关记录 -->
Type % 2 = 1
AND VerifyFlag = 0
AND UserName NOT IN ( 'floatbottle', 'fmessage', 'medianote','filehelper' )
AND UserName NOT LIKE '%@chatroom'
<!-- 以下是动态 SQL 条件判断,如果传入的 ContactDTO 对象中的 remark 属性不为空且不为空字符串,
则添加相应的模糊查询条件,用于根据备注进行筛选查询 -->
<if test="contactDTO.remark!= null and contactDTO.remark!= ''">
AND Remark LIKE '%' || #{contactDTO.remark} || '%'
</if>
<if test="contactDTO.nickName != null and contactDTO.nickName != ''">
<!-- 同理,根据传入的 ContactDTO 对象中的 nickName 属性添加模糊查询条件,用于按昵称筛选查询 -->
<if test="contactDTO.nickName!= null and contactDTO.nickName!= ''">
AND NickName LIKE '%' || #{contactDTO.nickName} || '%'
</if>
<if test="contactDTO.labels != null and contactDTO.labels != ''">
<!-- 根据传入的 ContactDTO 对象中的 labels 属性添加模糊查询条件,用于按标签筛选查询,
这里的逻辑是判断标签列表中是否包含指定的标签 -->
<if test="contactDTO.labels!= null and contactDTO.labels!= ''">
AND (',' || LabelIDList || ',') LIKE '%' || #{contactDTO.labels} || '%'
</if>
<if test="contactDTO.describe != null and contactDTO.describe != ''">
<!-- 根据传入的 ContactDTO 对象中的 describe 属性添加模糊查询条件,用于按描述筛选查询 -->
<if test="contactDTO.describe!= null and contactDTO.describe!= ''">
AND Reserved6 LIKE '%' || #{contactDTO.describe} || '%'
</if>
ORDER BY COALESCE(NULLIF(RemarkPYInitial, ''), PYInitial)
<!-- 按照特定规则对查询结果进行排序,优先使用 RemarkPYInitial 字段(如果不为空),
否则使用 PYInitial 字段进行排序 -->
ORDER BY COALESCE(NULLIF(RemarkPYInitial, ''), PYInitial)
</select>
<!-- 查询所有联系人 -->
<!-- 名为 "queryAllContact" 的查询语句配置,用于查询所有符合特定基本条件的联系人信息,
返回结果类型为 com.xcs.wx.domain.vo.AllContactVO -->
<select id="queryAllContact" resultType="com.xcs.wx.domain.vo.AllContactVO">
SELECT
c.UserName as userName,
@ -44,14 +61,17 @@
Contact c
WHERE
Type % 2 = 1
AND VerifyFlag = 0
AND UserName NOT IN ( 'floatbottle', 'fmessage', 'medianote','filehelper' )
AND UserName NOT LIKE '%@chatroom'
AND VerifyFlag = 0
AND UserName NOT IN ( 'floatbottle', 'fmessage', 'medianote','filehelper' )
AND UserName NOT LIKE '%@chatroom'
ORDER BY COALESCE(NULLIF(RemarkPYInitial, ''), PYInitial)
</select>
<!-- 查询联系人与公众号的Id -->
<!-- 名为 "getContactWithMp" 的查询语句配置用于查询联系人与公众号的别名alias信息
返回结果类型为 java.lang.String会将符合条件的联系人别名以及符合特定公众号条件的别名合并返回 -->
<select id="getContactWithMp" resultType="java.lang.String">
<!-- 使用 <![CDATA[ ]]> 标签来包裹 SQL 语句,这样可以避免 XML 解析器对 SQL 中的特殊字符进行错误解析,
比如这里的 UNION ALL 等操作符 -->
<![CDATA[
SELECT
CASE WHEN c.Alias IS NULL OR c.Alias = '' THEN c.UserName ELSE c.Alias END AS alias
@ -71,7 +91,8 @@
]]>
</select>
<!-- 统计联系人数量 -->
<!-- 名为 "countContact" 的查询语句配置,用于统计符合特定条件的联系人的数量,
返回结果类型为 java.lang.Integer -->
<select id="countContact" resultType="java.lang.Integer">
SELECT
count(*)
@ -79,12 +100,13 @@
Contact c
WHERE
Type % 2 = 1
AND VerifyFlag = 0
AND UserName NOT IN ( 'floatbottle', 'fmessage', 'medianote','filehelper' )
AND UserName NOT LIKE '%@chatroom';
AND VerifyFlag = 0
AND UserName NOT IN ( 'floatbottle', 'fmessage', 'medianote','filehelper' )
AND UserName NOT LIKE '%@chatroom';
</select>
<!-- 导出联系人 -->
<!-- 名为 "exportContact" 的查询语句配置,用于导出符合特定条件的联系人相关信息,
返回结果类型为 com.xcs.wx.domain.vo.ExportContactVO -->
<select id="exportContact" resultType="com.xcs.wx.domain.vo.ExportContactVO">
SELECT
c.UserName as userName,
@ -102,4 +124,4 @@
AND UserName NOT LIKE '%@chatroom'
</select>
</mapper>
</mapper>

@ -1,17 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 定义了一个 MyBatis 的映射器mappernamespace 属性指定了该映射器对应的接口全限定名,
通过这个对应关系MyBatis 框架能够将对应的接口方法与下面定义的 SQL 语句进行关联,以实现数据库操作 -->
<mapper namespace="com.xcs.wx.mapper.HardLinkImageAttributeMapper">
<!-- 查询图片地址 -->
<!-- 名为 "queryHardLinkImage" 的查询语句配置,其功能是用于查询图片地址,
返回结果类型为 java.lang.String意味着查询结果将以字符串的形式返回 -->
<select id="queryHardLinkImage" resultType="java.lang.String">
<!-- 具体的 SQL 查询语句,通过拼接字符串的方式来构造图片地址。从 HardLinkImageAttribute 表、HardLinkImageID 表(通过两次左连接)中获取相关数据,
按照特定格式拼接出图片的完整存储路径 -->
SELECT
'\\FileStorage\MsgAttach\\' || hli1.Dir || '\\' || 'Image' || '\\' || hli2.Dir || '\\' || hlia.FileName
'\\FileStorage\MsgAttach\\' || hli1.Dir || '\\' || 'Image' || '\\' || hli2.Dir || '\\' || hlia.FileName
FROM
HardLinkImageAttribute hlia
LEFT JOIN HardLinkImageID hli1 ON hlia.DirID1 = hli1.DirId
LEFT JOIN HardLinkImageID hli2 ON hlia.DirID2 = hli2.DirId
HardLinkImageAttribute hlia
LEFT JOIN HardLinkImageID hli1 ON hlia.DirID1 = hli1.DirId
LEFT JOIN HardLinkImageID hli2 ON hlia.DirID2 = hli2.DirId
WHERE
hlia.Md5=#{md5} LIMIT 1
<!-- 设置查询条件,筛选出 Md5 值与传入参数(通过 #{md5} 占位符表示MyBatis 会在执行时替换为实际传入的值)相等的记录,
并且使用 LIMIT 1 限制只返回一条符合条件的记录 -->
hlia.Md5=#{md5} LIMIT 1
</select>
</mapper>
</mapper>

@ -1,17 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 这是一个 MyBatis 的映射器mapper配置标签namespace 属性指定了该映射器对应的接口全限定名。
MyBatis 通过这个对应关系,能够将接口中的方法与下面定义的具体 SQL 语句相关联,从而实现数据库操作 -->
<mapper namespace="com.xcs.wx.mapper.HardLinkVideoAttributeMapper">
<!-- 查询视频 -->
<!-- 名为 "queryHardLinkVideo" 的查询语句配置标签,其目的是用于查询视频相关信息,
这里返回结果类型resultType设置为 java.lang.String表示查询到的最终结果会以字符串的形式返回 -->
<select id="queryHardLinkVideo" resultType="java.lang.String">
<!-- 具体的 SQL 查询语句部分,通过对多个表中的字段进行字符串拼接操作,来构造出视频文件的存储路径字符串。
从 HardLinkVideoAttribute 表出发通过左连接LEFT JOINHardLinkVideoID 表两次(分别关联不同的字段)获取相关的目录信息 -->
SELECT
'\\FileStorage\MsgAttach\\' || hlv1.Dir || '\\' || 'Image' || '\\' || hlv2.Dir || '\\' || hlva.FileName
'\\FileStorage\MsgAttach\\' || hlv1.Dir || '\\' || 'Image' || '\\' || hlv2.Dir || '\\' || hlva.FileName
FROM
HardLinkVideoAttribute hlva
LEFT JOIN HardLinkVideoID hlv1 ON hlva.DirID1 = hlv1.DirId
LEFT JOIN HardLinkVideoID hlv2 ON hlva.DirID2 = hlv2.DirId
HardLinkVideoAttribute hlva
LEFT JOIN HardLinkVideoID hlv1 ON hlva.DirID1 = hlv1.DirId
LEFT JOIN HardLinkVideoID hlv2 ON hlva.DirID2 = hlv2.DirId
WHERE
hlva.Md5=#{md5} LIMIT 1
<!-- 这里是查询的关键条件限定,通过判断 HardLinkVideoAttribute 表中的 Md5 字段值与传入的参数(使用 #{md5} 占位符表示,
在实际执行时MyBatis 会将对应传入的实际值替换进来)相等,来筛选出符合条件的记录。同时使用 LIMIT 1 限制只返回一条符合条件的记录,
通常意味着查找唯一匹配的视频相关记录 -->
hlva.Md5=#{md5} LIMIT 1
</select>
</mapper>
</mapper>

@ -1,9 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 定义了一个 MyBatis 的映射器mappernamespace 属性指定了该映射器对应的接口全限定名,
MyBatis 通过这种对应关系,可以将接口中的方法与下面定义的 SQL 语句进行关联,实现对数据库的操作 -->
<mapper namespace="com.xcs.wx.mapper.MsgMapper">
<!-- 定义名为 "msgResultMap" 的结果映射,用于将查询结果中的数据映射到 com.xcs.wx.domain.Msg 类型的 Java 对象上。
通过各个 <result> 标签明确了数据库表列与对象属性之间的对应关系 -->
<resultMap id="msgResultMap" type="com.xcs.wx.domain.Msg">
<!-- 将查询结果中名为 "talkerId" 的列的值映射到 Msg 对象的 talkerId 属性上 -->
<result property="talkerId" column="talkerId" />
<result property="msgSvrId" column="msgSvrId" />
<result property="type" column="type" />
@ -26,43 +31,49 @@
<result property="reserved4" column="reserved4" />
<result property="reserved5" column="reserved5" />
<result property="reserved6" column="reserved6" />
<!-- 将名为 "bytesExtra" 的列的值映射到 Msg 对象的 bytesExtra 属性上,并指定了类型处理器为 ByteArrayTypeHandler
用于处理字节数组类型的数据转换 -->
<result property="bytesExtra" column="bytesExtra" typeHandler="org.apache.ibatis.type.ByteArrayTypeHandler"/>
<result property="bytesTrans" column="bytesTrans" typeHandler="org.apache.ibatis.type.ByteArrayTypeHandler"/>
<result property="compressContent" column="compressContent" typeHandler="org.apache.ibatis.type.ByteArrayTypeHandler"/>
</resultMap>
<!-- 微信消息类型及其分布统计 -->
<!-- 名为 "msgTypeDistribution" 的查询语句配置,用于统计微信消息类型及其分布情况,
返回结果类型为 com.xcs.wx.domain.vo.MsgTypeDistributionVO即按照不同消息类型和子类型进行分类统计 -->
<select id="msgTypeDistribution" resultType="com.xcs.wx.domain.vo.MsgTypeDistributionVO">
<!-- SQL 查询语句,使用 CASE WHEN 语句根据消息的 Type 和 SubType 字段值来判断消息类型,
并将其转换为对应的中文描述(如文本、图片等),然后通过 COUNT(*) 统计每种类型消息的数量 -->
SELECT
CASE
WHEN Type = 1 AND SubType = 0 THEN '文本'
WHEN Type = 3 AND SubType = 0 THEN '图片'
WHEN Type = 34 AND SubType = 0 THEN '语音'
WHEN Type = 43 AND SubType = 0 THEN '视频'
WHEN Type = 47 AND SubType = 0 THEN '动画表情'
WHEN Type = 49 AND SubType = 1 THEN '特殊文本消息'
WHEN Type = 49 AND SubType = 5 THEN '卡片式链接'
WHEN Type = 49 AND SubType = 6 THEN '文件'
WHEN Type = 49 AND SubType = 8 THEN 'GIF表情'
WHEN Type = 49 AND SubType = 19 THEN '合并转发聊天记录'
WHEN Type = 49 AND SubType IN (33, 36) THEN '小程序分享'
WHEN Type = 49 AND SubType = 57 THEN '引用消息'
WHEN Type = 49 AND SubType = 63 THEN '视频号直播'
WHEN Type = 49 AND SubType = 87 THEN '群公告'
WHEN Type = 49 AND SubType = 88 THEN '视频号直播'
WHEN Type = 49 AND SubType = 2000 THEN '转账消息'
WHEN Type = 49 AND SubType = 2003 THEN '红包封面'
WHEN Type = 10000 AND SubType = 0 THEN '系统通知'
WHEN Type = 10000 AND SubType = 4 THEN '拍一拍'
WHEN Type = 10000 AND SubType = 8000 THEN '群聊邀请通知'
ELSE '其他类型'
END AS type,
COUNT(*) as value
CASE
WHEN Type = 1 AND SubType = 0 THEN '文本'
WHEN Type = 3 AND SubType = 0 THEN '图片'
WHEN Type = 34 AND SubType = 0 THEN '语音'
WHEN Type = 43 AND SubType = 0 THEN '视频'
WHEN Type = 47 AND SubType = 0 THEN '动画表情'
WHEN Type = 49 AND SubType = 1 THEN '特殊文本消息'
WHEN Type = 49 AND SubType = 5 THEN '卡片式链接'
WHEN Type = 49 AND SubType = 6 THEN '文件'
WHEN Type = 49 AND SubType = 8 THEN 'GIF表情'
WHEN Type = 49 AND SubType = 19 THEN '合并转发聊天记录'
WHEN Type = 49 AND SubType IN (33, 36) THEN '小程序分享'
WHEN Type = 49 AND SubType = 57 THEN '引用消息'
WHEN Type = 49 AND SubType = 63 THEN '视频号直播'
WHEN Type = 49 AND SubType = 87 THEN '群公告'
WHEN Type = 49 AND SubType = 88 THEN '视频号直播'
WHEN Type = 49 AND SubType = 2000 THEN '转账消息'
WHEN Type = 49 AND SubType = 2003 THEN '红包封面'
WHEN Type = 10000 AND SubType = 0 THEN '系统通知'
WHEN Type = 10000 AND SubType = 4 THEN '拍一拍'
WHEN Type = 10000 AND SubType = 8000 THEN '群聊邀请通知'
ELSE '其他类型'
END AS type,
COUNT(*) as value
FROM MSG
GROUP BY Type, SubType;
</select>
<!-- 统计过去 15 天每天的发送和接收消息数量 -->
<!-- 名为 "countRecentMsgs" 的查询语句配置,用于统计过去 15 天每天的发送和接收消息数量,
返回结果类型为 com.xcs.wx.domain.vo.CountRecentMsgsVO会分别统计出发送数量和接收数量两个类别 -->
<select id="countRecentMsgs" resultType="com.xcs.wx.domain.vo.CountRecentMsgsVO">
SELECT
strftime( '%m-%d', CreateTime, 'unixepoch', 'localtime' ) AS type,
@ -73,7 +84,7 @@
WHERE
DATE( CreateTime, 'unixepoch', 'localtime' ) >= DATE( 'now', '-15 days', 'localtime' )
GROUP BY
strftime( '%Y-%m-%d', CreateTime, 'unixepoch', 'localtime' )
strftime( '%Y-%m-d', CreateTime, 'unixepoch', 'localtime' )
UNION ALL
SELECT
strftime( '%m-%d', CreateTime, 'unixepoch', 'localtime' ) AS type,
@ -84,13 +95,14 @@
WHERE
DATE( CreateTime, 'unixepoch', 'localtime' ) >= DATE( 'now', '-15 days', 'localtime' )
GROUP BY
strftime( '%Y-%m-%d', CreateTime, 'unixepoch', 'localtime' )
strftime( '%Y-%m-d', CreateTime, 'unixepoch', 'localtime' )
ORDER BY
type,
category
</select>
<!-- 最近一个月内微信互动最频繁的前10位联系人 -->
<!-- 名为 "topContacts" 的查询语句配置,用于查找最近一个月内微信互动最频繁的前 10 位联系人,
返回结果类型为 com.xcs.wx.domain.vo.TopContactsVO通过统计与每个联系人的消息交互次数来确定互动频繁程度 -->
<select id="topContacts" resultType="com.xcs.wx.domain.vo.TopContactsVO">
SELECT
StrTalker as userName,
@ -106,7 +118,8 @@
total DESC
</select>
<!-- 统计发送消息数量 -->
<!-- 名为 "countSent" 的查询语句配置,用于统计当天发送消息的数量,返回结果类型为 java.lang.Integer
通过判断 IsSender 字段为 1表示发送方的记录数量来统计发送消息数 -->
<select id="countSent" resultType="java.lang.Integer">
SELECT
COALESCE( SUM( CASE WHEN IsSender = 1 THEN 1 ELSE 0 END ), 0 ) AS SentMessages
@ -116,7 +129,8 @@
DATE( CreateTime, 'unixepoch', 'localtime' ) = DATE( 'now', 'localtime' );
</select>
<!-- 统计接受消息数量 -->
<!-- 名为 "countReceived" 的查询语句配置,用于统计当天接收消息的数量,返回结果类型为 java.lang.Integer
通过判断 IsSender 字段为 0表示接收方的记录数量来统计接收消息数 -->
<select id="countReceived" resultType="java.lang.Integer">
SELECT
COALESCE( SUM( CASE WHEN IsSender = 0 THEN 1 ELSE 0 END ), 0 ) AS ReceivedMessages
@ -126,4 +140,4 @@
DATE( CreateTime, 'unixepoch', 'localtime' ) = DATE( 'now', 'localtime' );
</select>
</mapper>
</mapper>

@ -1,29 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 这是一个 MyBatis 的映射器mapper配置namespace 属性指定了该映射器对应的接口全限定名。
MyBatis 会依据此对应关系,将对应的接口方法与下面定义的 SQL 语句进行关联,从而实现数据库操作 -->
<mapper namespace="com.xcs.wx.mapper.SessionMapper">
<!-- 查询会话 -->
<!-- 名为 "querySession" 的查询语句配置,其功能是用于查询会话相关信息,
返回结果类型为 com.xcs.wx.domain.vo.SessionVO意味着查询结果将会被映射到对应的 SessionVO 类型的对象中 -->
<select id="querySession" resultType="com.xcs.wx.domain.vo.SessionVO">
<!-- 具体的 SQL 查询语句部分,从 Session 表、ContactHeadImgUrl 表以及 Contact 表中查询并获取会话相关的数据,
通过多表连接LEFT JOIN的方式关联各表以获取更全面的信息 -->
SELECT
s.strUsrName AS userName,
s.nTime AS time,
s.strContent AS content,
chiu.smallHeadImgUrl AS headImgUrl,
CASE
WHEN c.Remark IS NULL OR c.Remark = '' THEN
CASE WHEN c.NickName IS NULL OR c.NickName = '' THEN s.strNickName ELSE c.NickName
END ELSE c.Remark
END AS nickName
s.strUsrName AS userName, <!-- 将 Session 表中的 strUsrName 字段值作为 userName 字段返回 -->
s.nTime AS time, <!-- 将 Session 表中的 nTime 字段值作为 time 字段返回 -->
s.strContent AS content, <!-- 将 Session 表中的 strContent 字段值作为 content 字段返回 -->
chiu.smallHeadImgUrl AS headImgUrl, <!-- 将 ContactHeadImgUrl 表中的 smallHeadImgUrl 字段值作为 headImgUrl 字段返回 -->
CASE
WHEN c.Remark IS NULL OR c.Remark = '' THEN <!-- 判断 Contact 表中的 Remark 字段是否为空,如果为空则进入内层判断 -->
CASE WHEN c.NickName IS NULL OR c.NickName = '' THEN s.strNickName ELSE c.NickName
END ELSE c.Remark
END AS nickName <!-- 根据上述嵌套的条件判断,确定最终的 nickName 字段值,优先使用 Remark若 Remark 为空则看 NickName若都为空则使用 Session 表中的 strNickName -->
FROM
Session s
LEFT JOIN ContactHeadImgUrl chiu ON s.strUsrName = chiu.usrName
LEFT JOIN Contact c ON c.UserName = s.strUsrName
Session s
LEFT JOIN ContactHeadImgUrl chiu ON s.strUsrName = chiu.usrName <!-- 通过用户名关联 Session 表和 ContactHeadImgUrl 表 -->
LEFT JOIN Contact c ON c.UserName = s.strUsrName <!-- 通过用户名关联 Session 表和 Contact 表 -->
WHERE
strUsrName NOT LIKE '%gh_%'
AND nOrder > 1
AND nMsgLocalID > 0
strUsrName NOT LIKE '%gh_%' <!-- 筛选条件,排除用户名以 'gh_' 开头的记录,通常这类可能是公众号相关记录 -->
AND nOrder > 1 <!-- 另一个筛选条件,只选择 nOrder 字段值大于 1 的记录 -->
AND nMsgLocalID > 0 <!-- 再一个筛选条件,只选择 nMsgLocalID 字段值大于 0 的记录 -->
ORDER BY
nTime DESC
nTime DESC <!-- 按照时间nTime 字段)降序排列查询结果,即最新的会话信息排在前面 -->
</select>
</mapper>
</mapper>

@ -1,18 +1,39 @@
syntax = "proto3";
// 使 Protocol Buffers 3
// proto3
option java_outer_classname = "MsgProto";
// Java Java
// 使 Protocol Buffers .proto Java "MsgProto"
// 便 Java 使 Java
message SubMessage1 {
// "SubMessage1"
int32 field1 = 1;
// "field1" 32 int32
// "= 1" Protocol Buffers
// 1 15 1 15
int32 field2 = 2;
// "field2" 32 2 "field1" "SubMessage1"
}
// Protocol Buffers
message SubMessage2 {
int32 field1 = 1;
// "SubMessage2" "field1" 32 1 "SubMessage1"
string field2 = 2;
// "SubMessage2" "field2"string 2 "SubMessage2"
}
//
message MessageBytesExtra {
// "MessageBytesExtra"
SubMessage1 message1 = 1;
// "MessageBytesExtra" "message1" "SubMessage1" 1
// "SubMessage1"
repeated SubMessage2 message2 = 3;
}
// "MessageBytesExtra" "message2" "SubMessage2"使 "repeated"
// "SubMessage2" 3 "SubMessage2"
}

@ -1,20 +1,41 @@
syntax = "proto3";
// 使 Protocol Buffers 3
// proto3
option java_outer_classname = "ChatRoomProto";
// Java 使 Protocol Buffers Java "ChatRoomProto"
// Java 便 Java 使
// "ChatRoom"
message ChatRoom {
repeated Member members = 1;
// "members" "Member" 使 "repeated"
// "Member" 1
//
int32 field2 = 2;
// "field2" 32 int32 2
int32 field3 = 3;
// "field3" 32 3
int32 field4 = 4;
// "field4" 32 4使
int32 roomCapacity = 5;
// "roomCapacity" 32 5
int32 field6 = 6;
// "field6" 32 6
int64 field7 = 7;
// "field7" 64 int64 7
int64 field8 = 8;
// "field8" 64 8
}
// Protocol Buffers
// "Member" 便 "ChatRoom"
message Member {
string wxId = 1;
// "wxId" string 1 ID 便
string remark = 2;
// "remark" 2
int32 state = 3;
// "state" 32 3线
}

@ -2,6 +2,8 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!-- 定义该项目的父项目相关信息,当前项目会继承父项目的部分配置、依赖等内容 -->
<parent>
<artifactId>wx-dump-4j</artifactId>
<groupId>com.xcs.wx</groupId>
@ -9,39 +11,54 @@
<relativePath>../pom.xml</relativePath>
</parent>
<!-- Maven 项目对象模型POM的版本号一般固定为 4.0.0 -->
<modelVersion>4.0.0</modelVersion>
<!-- 当前项目的构件标识符,也就是项目最终生成的构件(如 jar 包等)的名称 -->
<artifactId>wx-dump-dist</artifactId>
<!-- 项目依赖配置部分,这里列出了项目运行所需要依赖的其他库 -->
<dependencies>
<!-- 引入名为 wx-dump-admin 的项目作为本项目的依赖,通常意味着本项目在运行时需要依赖该项目所提供的功能或类等 -->
<dependency>
<groupId>com.xcs.wx</groupId>
<artifactId>wx-dump-admin</artifactId>
</dependency>
</dependencies>
<!-- 项目构建配置文件中的 profiles 部分,用于定义不同的构建配置文件,根据不同的场景(如开发环境、测试环境、发布环境等)可以有不同的配置 -->
<profiles>
<!-- 定义一个名为 "release" 的构建配置文件,用于发布相关的构建设置 -->
<profile>
<id>release</id>
<!-- activation 元素用于配置该配置文件何时被激活,这里设置 activeByDefault 为 false表示默认情况下该配置文件不会被激活
需要手动指定或者根据其他条件来激活它 -->
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<!-- 定义项目最终生成的构件(如 jar 包等)的名称,在这里设置为 "wx-dump-4j" -->
<finalName>wx-dump-4j</finalName>
<plugins>
<!-- 配置 Maven Assembly 插件,该插件用于将项目的各种资源、依赖等打包成一个可分发的包,方便部署等操作 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<!-- descriptors 元素用于指定该插件所使用的描述文件,这里通过一个 Maven 属性(${project.basedir})指向项目根目录下的
src/main/assembly/binary.xml 文件作为描述文件,该文件定义了具体的组装打包规则 -->
<descriptors>
<descriptor>${project.basedir}/src/main/assembly/binary.xml</descriptor>
</descriptors>
</configuration>
<executions>
<!-- 定义插件的执行配置,每个 execution 代表一次插件的执行操作 -->
<execution>
<id>bin</id>
<!-- 定义该插件执行的阶段,这里设置为 "package" 阶段,表示在 Maven 执行到打包阶段时会执行该插件 -->
<phase>package</phase>
<goals>
<!--插件执行的具体目标,这里设置为 "single",表示按照配置文件中定义的规则进行单次组装打包操作 -->
<goal>single</goal>
</goals>
</execution>

@ -1,23 +1,35 @@
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<!-- 组装配置的唯一标识符,一般用于区分不同的组装配置,在这里定义为 "bin",可以在 Maven 构建命令中通过指定该 id 来应用对应的组装规则 -->
<id>bin</id>
<!-- 指定最终组装生成的文件格式,这里设置为 "tar.gz",表示会将相关文件打包成一个 tar.gz 格式的压缩包 -->
<formats>
<format>tar.gz</format>
</formats>
<!-- 是否在打包后的压缩包内包含项目的基础目录结构,设置为 "true" 表示包含,这样解压后会看到对应的目录结构 -->
<includeBaseDirectory>true</includeBaseDirectory>
<!-- 定义打包后压缩包内的基础目录名称,这里使用了一个 Maven 属性(${project.build.finalName})来动态生成目录名,
通常会基于项目最终构建的名称加上 "-bin" 后缀作为基础目录名 -->
<baseDirectory>${project.build.finalName}-bin</baseDirectory>
<!-- 文件集配置部分,用于指定要包含在最终打包文件中的各类文件以及它们的放置位置等信息 -->
<fileSets>
<!-- 第一个文件集配置,用于将指定目录下的特定文件复制到打包后的指定目录中 -->
<fileSet>
<!-- 指定源文件所在的目录,这里是相对路径,指向项目中 wx-dump-admin/src/main/resources 目录,意味着会从该目录获取文件 -->
<directory>../wx-dump-admin/src/main/resources</directory>
<!-- 指定文件在打包后的输出目录,这里表示会将文件放置在打包后的 /conf 目录下 -->
<outputDirectory>/conf</outputDirectory>
<includes>
<!-- 定义要包含的文件匹配规则,这里表示只包含扩展名为.yml 的文件 -->
<include>*.yml</include>
</includes>
</fileSet>
<!-- 第二个文件集配置 -->
<fileSet>
<directory>../wx-dump-ui/dist</directory>
<outputDirectory>/html</outputDirectory>
@ -25,6 +37,7 @@
<include>**/*</include>
</includes>
</fileSet>
<!-- 第三个文件集配置 -->
<fileSet>
<directory>src/main/resources/bin</directory>
<lineEnding>windows</lineEnding>
@ -36,11 +49,15 @@
</fileSet>
</fileSets>
<!-- 依赖集配置部分,用于指定项目依赖的处理方式以及在打包后的放置位置等 -->
<dependencySets>
<dependencySet>
<!-- 指定依赖库在打包后的输出目录,这里表示会将依赖的库文件放置在打包后的 /lib 目录下 -->
<outputDirectory>/lib</outputDirectory>
<!-- 是否解压依赖库(如果是压缩格式的依赖,如一些包含原生代码的库可能是压缩形式),设置为 "false" 表示不解压 -->
<unpack>false</unpack>
<!-- 指定依赖的范围,这里设置为 "runtime",表示只包含运行时需要的依赖,编译时依赖不会包含在内 -->
<scope>runtime</scope>
</dependencySet>
</dependencySets>
</assembly>
</assembly>

@ -1,4 +1,6 @@
import { queryMsg } from '@/services/Msg';
// 从项目中相对路径为 '@/services/Msg' 的模块里导入名为 'queryMsg' 的函数,
// 从函数名推测它的功能大概率是向服务器端发起请求,获取指定条件下的聊天消息相关的数据,例如根据聊天对象、消息序号等条件来获取相应的聊天记录内容。
import { Avatar, Button, Card, Flex, Image, List, Typography } from 'antd';
import React, { useEffect, useRef, useState } from 'react';
import './Style/Chat.less';

@ -79,7 +79,7 @@ const ChatRoom: React.FC = () => {
setIsExporting(false);
setIsExportChatOpen(false);
};
//。
const handleExportChatOpen = async (record: ChatRoomItem) =>{
setIsExportChatOpen(true);
setUserName(record.chatRoomName);

@ -1,20 +1,43 @@
import { countRecentMsgs } from '@/services/DashBoard';
// 从项目中相对路径为 '@/services/DashBoard' 的模块里导入名为 'countRecentMsgs' 的函数,
// 从名字推测这个函数可能用于获取近期消息相关的数据,比如向服务器端发起请求获取近期消息的数量等信息。
import { Line } from '@ant-design/plots';
// 从 Ant Design 的图表库(@ant-design/plots中导入 'Line' 组件,这个组件通常用于绘制折线图,
// 在这里应该是用来展示消息数量随时间或其他维度变化的可视化效果。
import React, { useEffect, useState } from 'react';
// 导入 React 框架以及它的两个 hooks'useEffect' 和 'useState'。
// 'useEffect' 用于在函数组件中执行副作用操作,比如数据获取、订阅、手动修改 DOM 等;
// 'useState' 用于在函数组件中添加状态,让组件能够根据不同状态进行重新渲染。
const CountRecentMsg: React.FC = () => {
// 定义一个名为 'CountRecentMsg' 的函数式组件,它遵循 React.FCFunction Component类型定义也就是一个接收 props 并返回 React 元素的函数。
const [data, setData] = useState<CountRecentMsgItem[]>([]);
// 使用 'useState' hook 来创建一个名为 'data' 的状态变量,初始值是一个空数组,其类型被定义为 'CountRecentMsgItem' 类型的数组,
// 这个状态变量大概率用于存储从服务器获取到的消息数量相关的数据,后续会根据获取到的数据进行更新并用于图表展示。
const [isLoading, setIsLoading] = useState(false);
// 再使用 'useState' hook 创建另一个名为 'isLoading' 的状态变量,初始值为 false用于表示当前是否正在加载数据的状态
// 当发起数据请求时会将其设置为 true数据请求完成后再设置回 false方便在界面上展示加载提示等相关效果。
const getDailyMsgCount = async () => {
// 定义一个名为 'getDailyMsgCount' 的异步函数,用于获取每日消息数量的数据。
setIsLoading(true);
// 在发起数据请求前,先将 'isLoading' 状态设置为 true表示数据正在加载中这样可以在界面上显示相应的加载提示比如加载动画等
try {
const response = await countRecentMsgs();
// 调用之前导入的 'countRecentMsgs' 函数,它返回一个 Promise通过 'await' 等待这个 Promise 被 resolve即请求完成并返回数据
// 将返回的结果赋值给'response' 变量,这里的结果应该包含了消息数量相关的数据。
setData(response.data);
// 从'response' 中取出 'data' 属性(假设服务器返回的数据结构中有 'data' 字段存放实际要展示的数据),
// 并通过'setData' 函数更新 'data' 状态变量,这样组件会根据新的数据重新渲染,进而更新图表展示的内容。
} catch (error) {
console.error(error);
// 如果在请求数据过程中出现错误(比如网络问题、服务器返回错误等),通过 'console.error' 将错误信息打印到控制台,方便进行调试和错误排查。
}
setIsLoading(false);
// 无论请求成功还是失败,最终都将 'isLoading' 状态设置回 false表示数据加载完成隐藏加载提示等相关界面元素。
};
const config = {
@ -26,12 +49,22 @@ const CountRecentMsg: React.FC = () => {
},
colorField: 'category',
};
// 创建一个名为 'config' 的配置对象,用于配置 'Line' 图表组件的各项属性。
// 'data' 属性使用了之前定义的 'data' 状态变量,提供图表要展示的数据;
// 'xField' 和 'yField' 分别指定了图表中 X 轴和 Y 轴对应的数据字段名(假设数据结构中有 'type' 和 'value' 这样的字段用于标识坐标轴对应的数值);
//'style' 用于设置图表的样式,这里设置了折线的宽度为 2
// 'colorField' 指定了用于区分不同类别数据时依据的字段名(假设数据中有 'category' 字段来区分不同类型的消息等情况),不同类别数据会以不同颜色展示。
useEffect(() => {
getDailyMsgCount();
}, []);
// 使用 'useEffect' hook传入一个回调函数这里是调用 'getDailyMsgCount' 函数来获取数据)和一个空的依赖项数组 []。
// 空的依赖项数组表示这个副作用操作(获取数据)只会在组件初次挂载时执行一次,相当于组件加载完成后立即发起数据请求,获取消息数量数据用于图表展示。
return <Line loading={isLoading} {...config} />;
// 返回一个 'Line' 图表组件,将 'isLoading' 状态作为 'loading' 属性传递给 'Line' 组件,用于控制组件在数据加载时是否显示加载提示效果,
// 同时通过展开运算符 {...config} 将之前定义的 'config' 对象中的属性展开传递给 'Line' 组件,用于配置图表的具体展示效果。
};
export default CountRecentMsg;
// 将定义好的 'CountRecentMsg' 函数式组件作为默认导出,方便在其他模块中导入并使用这个组件来展示消息数量统计的折线图。

@ -1,7 +1,12 @@
import React, { useState, useEffect } from 'react';
// 从 React 库中导入 React 核心以及两个常用的 Hook'useState' 和 'useEffect'。
// 在这个组件中虽然没有实际用到 'useState'(用于管理组件的状态)和 'useEffect'(用于处理组件的副作用,比如数据获取、订阅等操作),但仍然进行了导入,以备后续可能的功能扩展使用。
import { GithubOutlined } from '@ant-design/icons';
// 从 Ant Design 的图标库中导入名为 'GithubOutlined' 的图标组件,这个图标呈现的是 GitHub 的标志样式,将用于在页面上直观地展示 GitHub 相关的链接入口。
const Github: React.FC = () => {
// 定义一个名为 'Github' 的函数式组件,遵循 React.FCFunction Component的类型定义也就是一个接收 props属性并返回 React 元素的函数,在这里它用于构建一个特定功能的 UI 组件。
return (
<div
style={{
@ -15,6 +20,15 @@ const Github: React.FC = () => {
<GithubOutlined />
</div>
);
// 返回一个 <div> 元素作为组件的 UI 结构呈现。
// 这个 <div> 元素设置了内联样式style 属性),通过 JavaScript 对象的形式定义了样式规则:
// - 'display: 'flex'' 表示将该 <div> 元素设置为弹性布局,方便对内部元素(这里主要是图标)进行排列布局,使其更符合页面设计需求。
// - 'height: 26' 设置了 <div> 元素的高度为 26 像素,确定了该组件在页面上占据的垂直空间大小。
// 同时,为这个 <div> 元素添加了一个点击事件处理函数onClick当用户点击这个 <div> 元素时,会执行内部的函数逻辑。
// 函数内部调用了 'window.open' 方法,传入一个 URL 地址https://github.com/xuchengsheng/wx-dump-4j作用是在新的浏览器窗口或标签页中打开指定的 GitHub 仓库页面,
// 方便用户访问项目对应的 GitHub 仓库,查看代码、提交记录等相关信息。
// 在 <div> 元素内部放置了 '<GithubOutlined />',也就是之前导入的 Ant Design 的 GitHub 图标组件,该图标会显示在页面上,作为可点击的 GitHub 链接的可视化标识。
};
export default Github;
// 将定义好的 'Github' 函数式组件作为默认导出,这样在其他 React 组件或者模块中就可以通过导入的方式使用这个组件,将其嵌入到更复杂的页面结构中,以提供指向 GitHub 仓库的入口功能。

@ -1,20 +1,43 @@
import { msgTypeDistribution } from '@/services/DashBoard';
// 从项目中相对路径为 '@/services/DashBoard' 的模块里导入名为'msgTypeDistribution' 的函数,
// 从函数名推测它的作用可能是向服务器端发起请求,获取消息类型分布相关的数据,比如不同类型消息所占的比例等信息。
import { Pie } from '@ant-design/plots';
// 从 Ant Design 的图表库(@ant-design/plots中导入 'Pie' 组件,'Pie' 组件通常用于绘制饼图,
// 在这里用于以可视化的方式展示消息类型的分布情况,使不同类型消息占比一目了然。
import React, { useEffect, useState } from 'react';
// 导入 React 框架以及两个常用的 React hooks'useEffect' 和 'useState'。
// 'useEffect' 用于在函数组件中执行副作用操作,像发起网络请求、订阅数据更新、操作 DOM 等;
// 'useState' 用于在函数组件中定义和管理状态,组件会根据状态的变化重新渲染。
const MsgCategory: React.FC = () => {
// 定义一个名为 'MsgCategory' 的函数式组件,遵循 React.FCFunction Component类型定义即它是一个接收 props属性并返回 React 元素的函数,用于构建特定的 UI 界面及相应功能。
const [data, setData] = useState<MsgTypeDistributionItem[]>([]);
// 使用 'useState' hook 创建一个名为 'data' 的状态变量,其初始值设置为一个空数组,类型被定义为 'MsgTypeDistributionItem' 类型的数组,
// 这个状态变量用于存储从服务器获取到的消息类型分布相关的数据,后续会根据实际获取的数据进行更新,以便在饼图中展示相应内容。
const [isLoading, setIsLoading] = useState(false);
// 再次使用 'useState' hook 创建另一个状态变量 'isLoading',初始值设为 false用于表示当前是否正在加载数据的状态
// 当发起数据请求时将其设置为 true请求完成后再设置回 false方便在界面上展示数据加载的提示效果比如显示加载动画等。
const getMsgTypeDistribution = async () => {
// 定义一个名为 'getMsgTypeDistribution' 的异步函数,用于获取消息类型分布的数据。
setIsLoading(true);
// 在发起数据请求前,先把 'isLoading' 状态变量设置为 true告知用户当前正在加载数据界面上可以据此显示相应的加载提示元素。
try {
const response = await msgTypeDistribution();
// 调用之前导入的'msgTypeDistribution' 函数,它返回一个 Promise通过 'await' 等待这个 Promise 被 resolve也就是请求完成并返回数据
// 将返回的结果赋值给'response' 变量,该结果应该包含了消息类型分布相关的数据内容。
setData(response.data);
// 从'response' 变量中取出 'data' 属性(假设服务器返回的数据结构中有 'data' 字段存放实际要展示的数据),
// 然后使用'setData' 函数更新 'data' 状态变量,这样组件会根据新的数据重新渲染,进而使饼图展示最新的消息类型分布情况。
} catch (error) {
console.error(error);
// 如果在请求数据过程中出现错误,比如网络连接问题、服务器返回错误等,通过 'console.error' 把错误信息打印到控制台,便于进行调试和错误排查。
}
setIsLoading(false);
// 无论数据请求成功与否,最后都将 'isLoading' 状态变量设置回 false表示数据加载已完成相应地可以隐藏界面上的加载提示元素。
};
const config = {
@ -34,12 +57,28 @@ const MsgCategory: React.FC = () => {
},
},
};
// 创建一个名为 'config' 的配置对象,用于设置 'Pie' 饼图组件的各项属性。
// 'data' 属性使用了前面定义的 'data' 状态变量,为饼图提供要展示的数据内容。
// 'title' 属性设置饼图的标题为 '消息类别',直观地告知用户该饼图展示的内容主题。
// 'angleField' 指定了在数据中用于确定每个扇形角度大小(也就是占比情况)所对应的字段名为 'value',意味着根据数据里 'value' 字段的值来划分各个扇形的大小比例。
// 'colorField' 设定依据 'type' 字段的值来确定每个扇形的颜色,以便区分不同类型的消息,不同类型消息对应的扇形会显示不同颜色。
// 'radius' 属性设置饼图的半径为 0.9(这里是相对值,基于图表容器的大小来确定实际半径大小),用于调整饼图在图表区域内的显示尺寸。
// 'tooltip' 用于配置当鼠标悬停在饼图扇形上时显示的提示信息,这里设置提示信息的标题为 'value',具体显示内容可能还会根据数据结构及相关配置进一步确定。
// 'legend' 用于配置图例相关属性,'color' 里面的设置如下:
// - 'title' 设置为 false表示不显示图例的标题使图例显示更简洁。
// - 'position' 设置为 'bottom',指定图例的位置在饼图下方,方便用户对照查看不同颜色扇形代表的消息类型。
// - 'rowPadding' 设置为 5可能是用于控制图例每行之间的间距优化图例的显示布局。
useEffect(() => {
getMsgTypeDistribution();
}, []);
// 使用 'useEffect' hook传入一个回调函数这里是调用 'getMsgTypeDistribution' 函数来获取数据)和一个空的依赖项数组 []。
// 空的依赖项数组意味着这个副作用操作(获取数据)只会在组件初次挂载时执行一次,即组件加载完成后马上发起数据请求,获取消息类型分布数据用于饼图展示。
return <Pie loading={isLoading} {...config} />;
// 返回一个 'Pie' 饼图组件,将 'isLoading' 状态变量作为 'loading' 属性传递给 'Pie' 组件,用于控制组件在数据加载过程中是否显示加载提示效果,
// 同时通过展开运算符 {...config} 将前面定义的 'config' 对象中的属性展开传递给 'Pie' 组件,以此配置饼图的具体展示样式和交互行为等内容。
};
export default MsgCategory;
// 将定义好的 'MsgCategory' 函数式组件作为默认导出,方便其他模块在需要展示消息类型分布情况时导入并使用这个组件,使其融入到更复杂的前端页面结构中。

@ -1,25 +1,52 @@
import { queryRecentUsedKeyWord } from '@/services/DashBoard';
// 从项目中相对路径为 '@/services/DashBoard' 的模块里导入名为 'queryRecentUsedKeyWord' 的函数,
// 从函数名推测它的功能大概率是向服务器端发起请求,以获取近期使用过的关键词相关的数据信息,例如关键词及其出现的频次等内容。
import { WordCloud } from '@ant-design/plots';
// 从 Ant Design 的图表库(@ant-design/plots中导入 'WordCloud' 组件,'WordCloud' 即词云图组件,
// 通常用于以可视化的方式呈现文本数据中不同关键词的重要程度或出现频率等情况,在这里是要展示近期使用关键词的相关信息。
import React, { useEffect, useState } from 'react';
// 导入 React 框架以及两个常用的 React hooks'useEffect' 和 'useState'。
// 'useEffect' 可用于在函数组件中处理副作用,像发起网络请求、订阅外部数据源、操作 DOM 等操作;
// 'useState' 则用于在函数组件里定义和管理状态,组件会依据状态的变化进行重新渲染。
const RecentUsedKeyWord: React.FC = () => {
// 定义一个名为 'RecentUsedKeyWord' 的函数式组件,遵循 React.FCFunction Component的类型定义意味着它是一个接收 props属性并返回 React 元素的函数,
// 其主要目的是构建出特定功能与 UI 展示效果的组件,用于展示近期使用关键词相关内容。
const [data, setData] = useState<RecentUsedKeyWordItem[]>([]);
// 使用 'useState' hook 创建一个名为 'data' 的状态变量,初始值设为一个空数组,其类型被定义为 'RecentUsedKeyWordItem' 类型的数组,
// 这个状态变量用于存放从服务器获取到的近期使用关键词相关的数据,后续会根据实际获取的数据进行更新,进而在词云图中展示相应的关键词信息。
const [isLoading, setIsLoading] = useState(false);
// 同样使用 'useState' hook 创建 'isLoading' 这个状态变量,初始值设定为 false它用于表示当前是否正在加载数据的状态
// 当发起数据请求时会将其设置为 true待请求完成后再变回 false方便在界面上展示相应的数据加载提示效果例如显示加载动画等。
const getRecentUsedKeyWord = async () => {
// 定义一个名为 'getRecentUsedKeyWord' 的异步函数,该函数的主要作用是获取近期使用的关键词数据。
setIsLoading(true);
// 在准备发起数据请求之前,先将 'isLoading' 状态变量的值设置为 true以此告知用户当前正在进行数据加载操作界面上可据此展示相应的加载提示元素。
try {
const response = await queryRecentUsedKeyWord();
// 调用之前导入的 'queryRecentUsedKeyWord' 函数,它返回一个 Promise通过 'await' 关键字等待这个 Promise 被成功 resolve也就是请求完成且返回了数据
// 然后将返回的结果赋值给'response' 变量,这里的结果应该包含了近期使用关键词相关的数据内容。
setData(response.data);
// 从'response' 变量中提取出 'data' 属性(假设服务器返回的数据结构中有 'data' 字段存放实际要展示的数据),
// 接着使用'setData' 函数来更新 'data' 状态变量,如此一来,组件会根据新的数据重新渲染,使得词云图能够展示最新的关键词情况。
} catch (error) {
console.error(error);
// 倘若在请求数据的过程中出现了错误,例如网络连接故障、服务器返回错误信息等情况,就通过 'console.error' 方法将错误信息打印到控制台,
// 方便后续进行调试以及错误排查工作。
}
setIsLoading(false);
// 不管数据请求最终是成功还是失败,都要把 'isLoading' 状态变量的值重新设置为 false表示数据加载操作已经结束相应地可以隐藏界面上的加载提示元素。
};
useEffect(() => {
getRecentUsedKeyWord();
}, []);
// 使用 'useEffect' hook传入一个回调函数此处是调用 'getRecentUsedKeyWord' 函数去获取数据)以及一个空的依赖项数组 []。
// 空的依赖项数组意味着这个副作用操作(也就是获取数据的操作)只会在组件初次挂载时执行一次,即组件加载完毕后会立即发起数据请求,获取近期使用关键词的数据用于词云图展示。
const config = {
paddingTop: 40,
@ -27,8 +54,17 @@ const RecentUsedKeyWord: React.FC = () => {
layout: { spiral: 'rectangular' },
colorField: 'text',
};
// 创建一个名为 'config' 的配置对象,用于设定 'WordCloud' 词云图组件的各项属性。
// 'paddingTop' 属性设置词云图组件上方的内边距为 40 像素,用于调整词云图在其容器内的布局位置,使其展示效果更符合页面设计需求。
// 'data' 属性使用了之前定义的 'data' 状态变量,为词云图提供要展示的关键词相关的数据内容,词云图会依据这些数据来生成相应的可视化效果。
// 'layout' 属性用于配置词云图中文字的布局方式,这里设置为 { spiral: 'rectangular' },表示采用矩形螺旋布局,也就是文字会按照矩形螺旋的形状排列,
// 不同的布局方式会呈现出不同的视觉效果,可根据实际需求进行选择。
// 'colorField' 属性指定了依据 'text' 字段的值来确定每个关键词文字在词云图中的颜色,这样可以让不同的关键词以不同颜色显示,增强可视化的区分度。
return <WordCloud loading={isLoading} {...config} />;
// 返回一个 'WordCloud' 词云图组件,将 'isLoading' 状态变量作为 'loading' 属性传递给 'WordCloud' 组件,以此来控制组件在数据加载期间是否显示加载提示效果,
// 同时通过展开运算符 {...config} 将前面定义的 'config' 对象中的属性展开传递给 'WordCloud' 组件,从而配置词云图的具体展示样式、布局以及颜色等相关内容。
};
export default RecentUsedKeyWord;
// 将定义好的 'RecentUsedKeyWord' 函数式组件作为默认导出,方便其他模块在需要展示近期使用关键词情况时,能够导入并使用这个组件,使其融入到更复杂的前端页面结构之中。

@ -1,30 +1,60 @@
import { statsPanel } from '@/services/DashBoard';
// 从项目中相对路径为 '@/services/DashBoard' 的模块里导入名为'statsPanel' 的函数,
// 从函数名推测它的作用大概率是向服务器端发起请求,获取用于展示在统计面板上的相关数据,例如好友数量、消息收发数量等信息。
import RcResizeObserver from 'rc-resize-observer';
// 导入 'rc-resize-observer' 这个库提供的 'RcResizeObserver' 组件,它通常用于监听组件尺寸的变化,
// 在这个代码中用于检测页面宽度变化,以便根据宽度来调整内部组件的布局方式,实现响应式布局效果。
import React, { useEffect, useState } from 'react';
// 导入 React 框架以及两个常用的 React hooks'useEffect' 和 'useState'。
// 'useEffect' 用于在函数组件中处理副作用,比如发起网络请求、订阅数据更新、操作 DOM 等操作;
// 'useState' 用于在函数组件里定义和管理状态,组件会根据状态的改变进行重新渲染。
import { StatisticCard } from '@ant-design/pro-components';
// 从 Ant Design 的专业组件库(@ant-design/pro-components中导入 'StatisticCard' 组件,
// 这个组件常用于以卡片形式展示统计数据,在这里用于展示各项统计指标(如好友数量、消息数量等),使数据展示更加直观、美观。
const Panel: React.FC = () => {
// 定义一个名为 'Panel' 的函数式组件,遵循 React.FCFunction Component的类型定义即它是一个接收 props属性并返回 React 元素的函数,
// 其主要功能是构建出一个具有特定统计数据展示功能以及响应式布局的 UI 组件。
const [responsive, setResponsive] = useState(false);
// 使用 'useState' hook 创建一个名为'responsive' 的状态变量,初始值设为 false用于表示当前组件是否处于需要响应式布局的状态
// 后续会根据页面宽度变化来更新这个状态,进而调整内部组件的排列方式(例如从行排列变为列排列等)。
const [data, setData] = useState<StatsPanel>();
// 再次使用 'useState' hook 创建 'data' 这个状态变量,初始值设为 undefined类型为 'StatsPanel',具体该类型的结构应该在其他地方定义),
// 它用于存储从服务器获取到的统计面板相关的数据,后续会根据实际获取的数据进行更新,以便在 'StatisticCard' 组件中展示具体的数值。
const imgStyle = {
display: 'block',
width: 42,
height: 42,
};
// 创建一个名为 'imgStyle' 的对象,用于定义图片的样式规则,通过 JavaScript 对象的形式来设置内联样式。
// 'display: 'block'' 表示将图片以块级元素显示,使其独占一行等布局特性符合预期;
// 'width: 42' 和 'height: 42' 分别设置图片的宽度和高度为 42 像素,确定了图片在展示时的尺寸大小。
const getStatsPanel = async () => {
// 定义一个名为 'getStatsPanel' 的异步函数,其主要目的是获取统计面板的数据。
try {
const response = await statsPanel();
// 调用之前导入的'statsPanel' 函数,它返回一个 Promise通过 'await' 等待这个 Promise 被 resolve也就是请求完成并返回数据
// 将返回的结果赋值给'response' 变量,这里的结果应该包含了要展示在统计面板上的各项数据内容。
setData(response.data);
// 从'response' 变量中取出 'data' 属性(假设服务器返回的数据结构中有 'data' 字段存放实际要展示的数据),
// 然后使用'setData' 函数更新 'data' 状态变量,这样组件会根据新的数据重新渲染,进而在对应的 'StatisticCard' 组件中展示最新的统计数值。
} catch (error) {
console.error(error);
// 如果在请求数据过程中出现错误,比如网络连接问题、服务器返回错误等,通过 'console.error' 把错误信息打印到控制台,便于进行调试和错误排查。
}
};
useEffect(() => {
getStatsPanel();
}, []);
// 使用 'useEffect' hook传入一个回调函数这里是调用 'getStatsPanel' 函数来获取数据)和一个空的依赖项数组 []。
// 空的依赖项数组意味着这个副作用操作(获取数据)只会在组件初次挂载时执行一次,即组件加载完成后立即发起数据请求,获取统计面板数据用于后续展示。
return (
<RcResizeObserver
@ -33,7 +63,7 @@ const Panel: React.FC = () => {
setResponsive(offset.width < 596);
}}
>
<StatisticCard.Group direction={responsive ? 'column' : 'row'}>
<StatisticCard.Group direction={responsive? 'column' : 'row'}>
<StatisticCard
statistic={{
title: '好友数量',
@ -58,37 +88,24 @@ const Panel: React.FC = () => {
alt="icon"
/>
),
}}
/>
<StatisticCard
statistic={{
title: '今日发送消息数量',
value: data?.sent,
icon: (
<img
style={imgStyle}
src="/img/icon-send-message-number.png"
alt="icon"
/>
),
}}
/>
<StatisticCard
statistic={{
title: '今日接受消息数量',
value: data?.received,
icon: (
<img
style={imgStyle}
src="/img/icon-receiver-message-number.png"
alt="icon"
/>
),
}}
/>
</StatisticCard.Group>
</RcResizeObserver>
);
};
/>
</StatisticCard.Group>
</RcResizeObserver>
);
// 返回一个由多个组件嵌套组成的 React 元素结构。
// 最外层是 'RcResizeObserver' 组件,它用于监听尺寸变化,设置了 'key' 属性为 "resize-observer",用于在 React 渲染机制中唯一标识这个组件实例。
// 同时传入 'onResize' 回调函数,当组件尺寸发生变化时(这里主要关注宽度变化),会获取到尺寸变化的偏移量信息(通过参数 'offset'
// 然后通过判断偏移量中的宽度offset.width是否小于 596 像素来更新'responsive' 状态变量,以此决定内部组件的布局方向。
// 在 'RcResizeObserver' 内部是 'StatisticCard.Group' 组件,它用于对多个 'StatisticCard' 组件进行分组管理,
// 通过 'direction' 属性根据'responsive' 状态来设置内部 'StatisticCard' 组件的排列方向,当'responsive' 为 true即页面宽度较窄排列方向为 'column'(列方向),
// 否则为 'row'(行方向),实现响应式布局效果。
// 每个 'StatisticCard' 组件用于展示一项具体的统计数据,通过'statistic' 属性传入一个对象来配置展示的内容:
// - 'title' 用于设置统计数据的标题,比如 "好友数量"、"群聊数量" 等,直观地告知用户该项数据代表的含义。
// - 'value' 用于设置要展示的具体数值,这里关联了 'data' 状态变量中的对应字段(如 'contact'、'chatRoom' 等,前提是 'data' 中包含这些字段且类型匹配),
// 会根据从服务器获取到的数据动态显示相应的数值。
// - 'icon' 用于设置一个图标元素,通过传入一个包含 <img> 标签的 React 元素来展示对应的图标,图标样式使用之前定义的 'imgStyle' 对象进行设置,
// 同时指定了图标对应的图片资源路径(如 "/img/icon-friend-number.png" 等以及图片的替代文本alt 属性),使图标展示更美观且符合语义。
};
export default Panel;
export default Panel;
// 将定义好的 'Panel' 函数式组件作为默认导出,方便其他模块在需要展示统计面板信息并且实现响应式布局时,导入并使用这个组件,将其融入到更复杂的前端页面结构之中。

@ -1,27 +1,58 @@
import { topContacts } from '@/services/DashBoard';
// 从项目中相对路径为 '@/services/DashBoard' 的模块里导入名为 'topContacts' 的函数,
// 从函数名推测它的功能大概率是向服务器端发起请求,获取最近一个月内微信互动最频繁的前 10 位联系人相关的数据信息,比如联系人昵称、头像链接、互动次数等内容。
import { Avatar } from 'antd';
// 从 Ant Design'antd')库中导入 'Avatar' 组件,'Avatar' 通常用于展示用户的头像,在这里用于显示联系人的头像,使界面展示更加直观形象。
import React, { useEffect, useState } from 'react';
// 导入 React 框架以及两个常用的 React hooks'useEffect' 和 'useState'。
// 'useEffect' 用于在函数组件中处理副作用,像发起网络请求、订阅数据更新、操作 DOM 等操作;
// 'useState' 用于在函数组件里定义和管理状态,组件会依据状态的变化进行重新渲染。
import styles from '../Style/TopContacts.less';
// 导入相对路径 '../Style/TopContacts.less' 对应的样式模块(这里假设是使用了 CSS 预处理器 LESS 编写的样式文件),
// 通过解构赋值等方式可以获取到其中定义的各类样式类名,用于给组件内的 HTML 元素添加相应的样式,实现自定义的界面外观设计。
import { Skeleton } from 'antd';
// 从 Ant Design'antd')库中导入 'Skeleton' 组件,'Skeleton' 常用于在数据加载过程中展示一个占位的骨架屏效果,告知用户数据正在加载中,提升用户体验。
const TopContacts: React.FC = () => {
// 定义一个名为 'TopContacts' 的函数式组件,遵循 React.FCFunction Component的类型定义即它是一个接收 props属性并返回 React 元素的函数,
// 其主要作用是构建出展示微信前 10 位频繁互动联系人信息的 UI 组件。
const [data, setData] = useState<TopContactsMonthlyItem[]>([]);
// 使用 'useState' hook 创建一个名为 'data' 的状态变量,初始值设为一个空数组,其类型被定义为 'TopContactsMonthlyItem' 类型的数组,
// 这个状态变量用于存储从服务器获取到的前 10 位联系人相关的数据,后续会根据实际获取的数据进行更新,以便在组件中展示各个联系人的详细信息。
const [isLoading, setIsLoading] = useState(false);
// 同样使用 'useState' hook 创建 'isLoading' 这个状态变量,初始值设定为 false它用于表示当前是否正在加载数据的状态
// 当发起数据请求时会将其设置为 true待请求完成后再变回 false方便在界面上展示相应的数据加载提示效果例如通过 'Skeleton' 组件显示骨架屏。
const getTop10ContactsMonthly = async () => {
// 定义一个名为 'getTop10ContactsMonthly' 的异步函数,其主要目的是获取最近一个月内微信互动最频繁的前 10 位联系人的数据。
setIsLoading(true);
// 在准备发起数据请求之前,先将 'isLoading' 状态变量的值设置为 true以此告知用户当前正在进行数据加载操作界面上可据此展示相应的加载提示元素比如显示 'Skeleton' 组件的骨架屏效果。
try {
const response = await topContacts();
// 调用之前导入的 'topContacts' 函数,它返回一个 Promise通过 'await' 关键字等待这个 Promise 被成功 resolve也就是请求完成且返回了数据
// 然后将返回的结果赋值给'response' 变量,这里的结果应该包含了前 10 位联系人相关的数据内容。
setData(response.data);
// 从'response' 变量中提取出 'data' 属性(假设服务器返回的数据结构中有 'data' 字段存放实际要展示的数据),
// 接着使用'setData' 函数来更新 'data' 状态变量,如此一来,组件会根据新的数据重新渲染,进而展示出最新的联系人相关信息。
} catch (error) {
console.error(error);
// 倘若在请求数据的过程中出现了错误,例如网络连接故障、服务器返回错误信息等情况,就通过 'console.error' 方法将错误信息打印到控制台,
// 方便后续进行调试以及错误排查工作。
}
setIsLoading(false);
// 不管数据请求最终是成功还是失败,都要把 'isLoading' 状态变量的值重新设置为 false表示数据加载操作已经结束相应地可以隐藏界面上的加载提示元素比如隐藏 'Skeleton' 组件的骨架屏效果。
};
useEffect(() => {
getTop10ContactsMonthly();
}, []);
// 使用 'useEffect' hook传入一个回调函数此处是调用 'getTop10ContactsMonthly' 函数去获取数据)以及一个空的依赖项数组 []。
// 空的依赖项数组意味着这个副作用操作(也就是获取数据的操作)只会在组件初次挂载时执行一次,即组件加载完毕后会立即发起数据请求,获取前 10 位联系人的数据用于后续展示。
return (
<Skeleton loading={isLoading} paragraph={{ rows: 13 }} active round>
@ -30,7 +61,7 @@ const TopContacts: React.FC = () => {
<ul className={styles.topContactList}>
{data.map((item, i) => (
<li key={item.nickName}>
<span className={`${styles.topContactItemNumber} ${i < 3 ? styles.active : ''}`}>
<span className={`${styles.topContactItemNumber} ${i < 3? styles.active : ''}`}>
{i + 1}
</span>
<Avatar size={30} src={item.headImgUrl} />
@ -44,6 +75,22 @@ const TopContacts: React.FC = () => {
</div>
</Skeleton>
);
// 返回一个由多个组件嵌套组成的 React 元素结构。
// 最外层是 'Skeleton' 组件,它用于在数据加载时展示骨架屏效果,通过 'loading' 属性绑定 'isLoading' 状态变量,根据其值来决定是否显示骨架屏,
// 'paragraph' 属性设置骨架屏中段落的行数为 13模拟出类似列表项加载的效果'active' 属性设置为 true 表示骨架屏有动画效果,增强视觉上的提示作用;'round' 属性可能使骨架屏元素的边角呈现圆角效果,使其更加美观。
// 在 'Skeleton' 组件内部是一个 <div> 元素,用于包裹整个联系人信息展示的内容结构。
// 首先是一个 <h4> 标题元素,显示 "最近一个月内微信互动最频繁的前 10 位联系人",直观地告知用户下方列表展示的内容主题。
// 接着是一个 <ul> 无序列表元素,通过设置 'className' 属性为从样式模块中获取的'styles.topContactList',应用对应的样式类来定义列表的外观样式,比如列表的间距、边框等样式属性。
// 在 <ul> 列表内部,通过使用数组的'map' 方法遍历 'data' 状态变量(也就是前 10 位联系人的数据数组),针对每个联系人数据项('item')和其索引('i')生成一个对应的 <li> 列表项元素,并且为每个 <li> 元素设置了唯一的 'key' 属性(使用联系人的昵称 'item.nickName'),方便 React 进行高效的列表渲染和更新操作。
// 在每个 <li> 列表项中:
// - 有一个 <span> 元素用于显示联系人的排名序号,通过设置 'className' 属性添加了'styles.topContactItemNumber' 样式类来定义序号的外观样式(比如字体大小、颜色等),
// 同时通过一个三元表达式判断索引 'i' 是否小于 3如果小于 3 则再添加'styles.active' 样式类,可能用于给排名前三的序号添加特殊的样式效果(比如加粗、变色等),
// 并在 <span> 元素内部显示序号值('i + 1')。
// - 接着是一个 'Avatar' 组件,通过设置'size' 属性为 30 来指定头像的尺寸大小(单位可能是像素),并通过'src' 属性传入联系人头像的图片链接('item.headImgUrl'),用于展示联系人的头像图片。
// - 然后又是一个 <span> 元素,设置 'className' 为'styles.topContactItemTitle' 样式类用于定义联系人昵称的显示样式,同时通过 'title' 属性设置了鼠标悬停时显示的提示文本为联系人昵称('item.nickName'
// 在元素内部也显示联系人的昵称,方便用户查看和识别联系人。
// - 最后还有一个 <span> 元素,用于显示与该联系人的互动次数等统计数据(这里只显示了 'item.total',具体含义取决于数据结构中的定义)。
};
export default TopContacts;
// 将定义好的 'TopContacts' 函数式组件作为默认导出,方便其他模块在需要展示微信互动频繁联系人信息时,能够导入并使用这个组件,使其融入到更复杂的前端页面结构之中。

@ -242,5 +242,5 @@ const Contact: React.FC = () => {
</PageContainer>
);
};
//
export default Contact;

@ -1,21 +1,32 @@
import { Card, Col, Row } from 'antd';
// 从 Ant Design 库中导入 'Card'(卡片组件,常用于将相关内容进行分组展示,使其在页面上有清晰的区域划分)、'Col'(网格布局中的列组件,用于控制内容在不同屏幕尺寸下所占的列数,实现响应式布局)、
// 'Row'(网格布局中的行组件,与 'Col' 配合使用,定义页面的行结构,规定内部列的排列方式)这三个组件,用于构建页面的布局结构以及对各个统计信息模块进行合理的展示分组。
import CountRecentMsg from './Components/CountRecentMsg';
import MsgCategory from './Components/MsgCategory';
import RecentUsedKeyWord from './Components/RecentUsedKeyWord';
import StatsPanel from './Components/StatsPanel';
import TopContacts from './Components/TopContacts';
// 导入多个自定义组件,这些组件分别位于项目的 './Components' 目录下,从组件名称推测它们各自负责展示不同类型的微信消息相关统计信息,例如 'CountRecentMsg' 可能用于展示近期消息数量,
// 'MsgCategory' 或许用于展示消息类别占比情况,'RecentUsedKeyWord' 大概是展示最近使用的关键字相关内容,'StatsPanel' 可能呈现一些总体的统计面板信息,'TopContacts' 则用于展示常用联系人相关统计数据,它们将被嵌入到当前页面的对应位置进行展示。
export default () => {
return (
<>
<StatsPanel />
// 首先渲染 'StatsPanel' 组件,这个组件会展示一些整体的统计信息面板内容,不过具体展示的内容取决于该组件内部的实现逻辑,它作为页面的第一个展示模块,给用户提供一个整体的数据概览。
<Card style={{ marginTop: 25 }} title="过去15天内每日微信消息数量统计">
// 使用 'Card' 组件创建一个卡片式的区域,设置'marginTop' 样式属性为 25 像素,使其与上方元素有一定的间隔距离,'title' 属性设置为 "过去15天内每日微信消息数量统计",直观地告知用户这个卡片区域展示的内容主题。
<Row>
// 在这个卡片内部,使用 'Row' 组件创建一行布局结构,用于放置后续的列组件以及对应的统计信息展示组件,通过行与列的组合实现灵活的页面布局。
<Col xl={18} lg={12} md={12} sm={24} xs={24}>
// 使用 'Col' 组件定义一个列,通过设置不同屏幕尺寸('xl' 表示超大屏幕、'lg' 表示大屏幕、'md' 表示中屏幕、'sm' 表示小屏幕、'xs' 表示超小屏幕)下所占的列数,来控制其在不同设备上的宽度表现,实现响应式布局,
// 这里在超大屏幕('xl')下占 18 列,在其他屏幕尺寸下占不同的列数,在这个列中放置 'CountRecentMsg' 组件,用于展示过去 15 天内每日微信消息数量的统计信息,使其在页面上占据合适的空间位置进行展示。
<CountRecentMsg />
</Col>
<Col xl={6} lg={12} md={12} sm={24} xs={24}>
// 同样使用 'Col' 组件定义另一个列,在不同屏幕尺寸下设置相应的列数,在这个列中放置 'TopContacts' 组件,用于展示常用联系人相关的统计信息,与前面的消息数量统计组件共同展示在同一行内,形成对比和关联的数据展示效果。
<TopContacts />
</Col>
</Row>
@ -27,14 +38,20 @@ export default () => {
marginTop: 24,
}}
>
// 再创建一个新的 'Row' 组件,设置 'gutter' 属性为 24这个属性用于定义列与列之间的间隔距离为 24 像素,使内部列之间有合适的空白间隔,同时设置'marginTop' 样式属性为 24 像素,与上方元素隔开一定距离,
// 用于放置另外两个统计信息展示模块,实现新的一行布局结构。
<Col xl={12} lg={24} md={24} sm={24} xs={24}>
// 使用 'Col' 组件定义一个列,在不同屏幕尺寸下设置相应的列数,在这个列中放置一个 'Card' 组件,用于再次创建一个卡片式的展示区域,设置 'title' 属性为 "过去15天内消息类别占比",表明这个卡片内展示的是消息类别占比相关的统计信息。
<Card title="过去15天内消息类别占比">
<MsgCategory />
// 在这个卡片内部放置 'MsgCategory' 组件,用于具体展示过去 15 天内消息类别占比的详细数据内容,通过卡片将其与其他内容区分开来,使其更具独立性和可读性。
</Card>
</Col>
<Col xl={12} lg={24} md={24} sm={24} xs={24}>
// 类似地,再使用 'Col' 组件定义另一个列,在不同屏幕尺寸下设置相应的列数,在这个列中放置另一个 'Card' 组件,设置 'title' 属性为 "最近使用的关键字",说明该卡片内展示的是与最近使用的关键字相关的统计信息。
<Card title="最近使用的关键字">
<RecentUsedKeyWord />
// 在这个卡片内部放置 'RecentUsedKeyWord' 组件,用于展示最近使用的关键字相关的具体内容,同样通过卡片进行分组展示,使页面布局更加清晰,不同类型的数据展示模块区分明显,方便用户查看和理解各项统计信息。
</Card>
</Col>
</Row>

@ -138,6 +138,7 @@ const DecryptTool: React.FC = () => {
align: 'center',
},
{
// 定义详情查看的模态框,内部再使用 ProTable 通过 getDatabase 函数获取对应微信的数据库信息进行展示,呈现数据库列表内容。
dataIndex: 'basePath1',
title: '解密进度',
search: false,

@ -1,12 +1,23 @@
import { queryFeeds } from '@/services/Feeds';
import { queryAllContact } from '@/services/Contact';
// 从对应服务模块导入查询动态Feeds和查询所有联系人的函数用于获取相关数据。
import { LikeOutlined, MessageOutlined, StarOutlined } from '@ant-design/icons';
// 导入 Ant Design 的图标组件,用于在界面上展示特定图标,增强可视化效果和交互提示。
import { PageContainer, ProList } from '@ant-design/pro-components';
import { Avatar, Col, Flex, Image, Row, Typography,Alert } from 'antd';
// 引入 PageContainer 作为页面整体容器ProList 用于展示列表数据,构建列表展示的基础框架。
import { Avatar, Col, Flex, Image, Row, Typography, Alert } from 'antd';
// 从 Ant Design 库导入多个常用组件,用于构建页面中头像、布局、图片展示、文本等各种元素。
import React from 'react';
import './Style/Feeds.less';
import { useEffect, useState } from 'react';
// 导入 React 核心库以及常用钩子函数useEffect 用于处理副作用useState 用于管理组件状态。
import dayjs from 'dayjs';
// 引入 dayjs 库,用于处理日期相关操作,比如日期格式转换等。
const IconText = ({ icon, text }: { icon: any; text: string }) => (
<span>
@ -14,12 +25,14 @@ const IconText = ({ icon, text }: { icon: any; text: string }) => (
{text}
</span>
);
// 定义一个函数组件 IconText用于组合图标和文本显示方便在界面上统一展示带图标的文本元素。
const { Text, Link } = Typography;
const Feeds: React.FC = () => {
const [allContact, setAllContact] = useState<{ [key: string]: { text: string } }>({});
// 使用 useState 定义 allContact 状态,用于存储所有联系人信息,初始化为空对象,后续会根据查询结果更新。
const getAllContact = async () => {
try {
@ -34,21 +47,18 @@ const Feeds: React.FC = () => {
console.error(error);
}
};
// 定义异步函数 getAllContact用于获取所有联系人信息将查询结果处理后存入 allContact 状态中。
useEffect(() => {
getAllContact();
}, []);
// 在组件挂载时调用 getAllContact 函数,获取一次联系人信息,只执行一次(依赖项为空数组)。
return (
<PageContainer>
<Alert
message="温馨提示"
description="从2024年4月24日开始微信朋友圈的图片暂时无法显示。经过我们的初步分析猜测这可能是由于某些限制导致的。不过请放心2024年4月24日之前发布的图片依然可以正常显示不受影响。"
type="warning"
style={{marginBottom:10}}
showIcon
closable
/>
<Alert>
// 展示一个提示框Alert向用户提示微信朋友圈图片显示的相关情况如特定时间后的图片暂时无法显示等信息。
</Alert>
<ProList<FeedsItem>
request={async (params) => {
try {
@ -58,92 +68,11 @@ const Feeds: React.FC = () => {
return [];
}
}}
search={{}}
bordered
itemLayout="vertical"
pagination={{
pageSize: 5,
showSizeChanger: false
}}
// ProList 配置了请求数据的函数(通过 queryFeeds 获取动态数据)、搜索相关设置、分页等属性,用于展示动态列表信息。
// (此处省略部分详细属性注释,各属性作用可参考 Ant Design Pro 组件文档了解)
metas={{
title: {
dataIndex: 'nickName',
search: false,
},
userName: {
title: '用户名',
valueType: 'select',
dataIndex: 'userName',
valueEnum: allContact,
},
strCreateTime:{
title: '创建时间',
key: 'createdAtRange',
dataIndex: 'createdAtRange',
valueType: 'dateRange',
search: {
transform: (value) => {
return {
startTime: dayjs(value[0]).unix(),
endTime: dayjs(value[1]).add(1, 'day').unix(),
};
},
},
},
avatar: {
dataIndex: 'headImgUrl',
search: false,
render: (_, record) => {
return <Avatar src={record.headImgUrl}></Avatar>;
},
},
description: {
dataIndex: 'contentDesc',
search: false,
},
actions: {
render: () => [
<IconText icon={StarOutlined} text="0" key="list-vertical-star-o" />,
<IconText icon={LikeOutlined} text="0" key="list-vertical-like-o" />,
<IconText icon={MessageOutlined} text="0" key="list-vertical-message" />,
],
},
content: {
search: false,
render: (_, record) => {
return (
<Flex vertical>
<Flex vertical className="nine-grid">
<Row gutter={[16, 8]}>
{record.medias.map((media, index) => (
<Col key={index} xs={24} sm={12} md={8} lg={8} xl={8}>
<Image
width={150}
height={150}
fallback="/img/404.png"
src={`/api/image/downloadImg?path=${encodeURIComponent(media.url)}`}
style={{ objectFit: 'cover' }}
/>
</Col>
))}
</Row>
</Flex>
<Flex>
<Text type="secondary">{record.strCreateTime}</Text>
</Flex>
<Link
href={`http://api.map.baidu.com/geocoder?address=${encodeURIComponent(
record.location.poiName,
)}&output=html`}
target="_blank"
className="location"
>
{record.location.poiName}
</Link>
</Flex>
);
},
},
// 通过 metas 配置列表中各项数据的展示细节,如标题、用户名、创建时间、头像、描述、操作按钮、具体内容等各部分如何展示及相关交互逻辑。
// 例如 avatar 部分配置了头像的数据源及渲染方式content 部分详细定义了动态内容(包含图片、时间、位置等)如何展示。
}}
/>
</PageContainer>

@ -1,18 +1,35 @@
import { DownloadOutlined } from '@ant-design/icons';
// 从 Ant Design 图标库导入 'DownloadOutlined' 图标,用于表示导出相关的操作按钮图标,增强可视化提示。
import type { ProColumns } from '@ant-design/pro-components';
// 导入 ProColumns 类型定义,用于规范 ProTable 组件列的相关配置类型,保证类型安全和正确使用。
import { ProDescriptions, ProTable } from '@ant-design/pro-components';
// 导入 ProTable 用于展示表格数据ProDescriptions 可用于展示详情描述信息,这里主要使用 ProTable 来呈现已删除好友相关数据列表。
import { PageContainer } from '@ant-design/pro-layout';
// 引入 PageContainer 作为页面的整体容器,提供统一的布局样式和结构基础。
import { Avatar, Button, Card, Divider, Flex, List, Modal, Space, Tag, Typography } from 'antd';
// 从 Ant Design 库导入多个常用组件,不过在这段代码里主要使用到 Button、Modal 等组件用于交互操作和弹出提示框等功能。
import React, { useState } from 'react';
// 导入 React 核心库以及 useState 钩子,用于在函数组件中定义和管理状态,实现响应式的界面更新。
import './Style/ChatRoom.less';
// 导入自定义样式文件,为组件添加特定的样式,使其呈现出符合需求的外观。
import {queryRecoverContact,exportRecoverContact} from "@/services/RecoverContact";
// 从指定服务模块导入两个函数queryRecoverContact 用于获取已删除好友列表数据exportRecoverContact 用于执行导出已删除好友数据的操作。
const ChatRoom: React.FC = () => {
const [isExportRecoverContactOpen, setIsExportRecoverContactOpen] = useState(false);
const [isExporting, setIsExporting] = useState(false);
// 使用 useState 定义两个状态isExportRecoverContactOpen 控制导出相关模态框的显示与隐藏isExporting 表示是否正在进行导出操作。
const handleExportContact = async () => {
// 定义异步函数处理导出联系人的操作逻辑,包括发起请求、处理下载等步骤。
setIsExporting(true);
try {
const response = await exportRecoverContact();
@ -31,88 +48,26 @@ const ChatRoom: React.FC = () => {
};
const columns: ProColumns<ChatRoomItem>[] = [
// 定义 ProTable 的列配置数组,指定每列展示的数据字段、对齐方式、宽度等属性,用于呈现已删除好友的相关信息。
{
title: '昵称',
dataIndex: 'nickname',
align: 'center',
width: '500px'
},
{
dataIndex: 'remark',
title: '备注',
align: 'center',
width: '500px'
},
{
dataIndex: 'alias',
title: '微信号',
search: false,
align: 'center',
}
// 其他列配置类似,分别展示备注、微信号等信息
];
return (
<PageContainer>
<ProTable<ChatRoomItem>
columns={columns}
cardBordered={{
search: true,
table: true,
}}
request={async (params) => {
try {
return queryRecoverContact(params);
} catch (error) {
console.error(error);
return [];
}
}}
revalidateOnFocus={false}
rowKey="chatRoomName"
search={{
labelWidth: 'auto',
}}
options={false}
pagination={{
pageSize: 10,
showSizeChanger: false
}}
headerTitle="已删除好友列表"
toolBarRender={() => [
<Button
onClick={() => setIsExportRecoverContactOpen(true)}
key="button"
icon={<DownloadOutlined/>}
type="primary"
>
</Button>,
]}
/>
<Modal
title="导出已删除好友"
open={isExportRecoverContactOpen}
footer={null}
onCancel={() => setIsExportRecoverContactOpen(false)}
>
<p style={{padding: '15px'}}>
</p>
<Flex justify="flex-end">
<Space>
<Button disabled={isExporting} onClick={() => setIsExportRecoverContactOpen(false)}>
</Button>
<Button
type="primary"
loading={isExporting}
disabled={isExporting}
onClick={() => handleExportContact()}
>
</Button>
</Space>
</Flex>
columns={columns}
// 配置 ProTable 的各项属性,如列信息、边框样式、数据请求函数、分页设置等,用于展示已删除好友列表并进行相关操作。
// 其中 request 属性绑定了 queryRecoverContact 函数用于获取数据toolBarRender 中添加了导出按钮来触发导出操作。
// (此处省略各属性详细注释,可参考 Ant Design Pro 文档了解各属性含义)
/>
<Modal>
// 定义模态框,用于在导出操作时弹出提示信息,告知用户相关注意事项,并提供取消和开始导出的按钮,按钮状态根据相应状态变量控制。
</Modal>
</PageContainer>
);

@ -1,41 +1,87 @@
import {querySession} from '@/services/Session';
// 从项目中相对路径为 '@/services/Session' 的模块里导入名为 'querySession' 的函数,
// 从函数名推测它的作用大概率是向服务器端发起请求,获取聊天会话相关的数据,例如聊天列表中的各个会话信息,像聊天对象名称、头像链接、最近消息内容等内容。
import {ProCard} from '@ant-design/pro-components';
// 从 Ant Design 的专业组件库(@ant-design/pro-components中导入 'ProCard' 组件,
// 'ProCard' 组件常用于构建具有特定样式和布局功能的卡片式容器,在这里用于搭建聊天列表以及具体聊天窗口等不同区域的外层布局结构,使界面更具层次感和美观性。
import {Avatar, List, Typography} from 'antd';
// 从 Ant Design'antd')库中导入多个组件,包括用于展示用户头像的 'Avatar' 组件、列表展示相关的 'List' 组件以及处理文本相关展示的 'Typography'(后续还从中解构出了 'Text' 组件用于更精细的文本展示控制),
// 这些组件将共同协作用于构建聊天列表中各个会话项的展示样式,比如展示头像、会话标题、消息摘要以及时间等信息。
import {useEffect, useState} from 'react';
// 导入 React 框架提供的两个常用 Hook'useState' 和 'useEffect'。
// 'useState' 用于在函数组件里定义和管理状态,使得组件能够根据状态的变化重新渲染,展示不同的界面内容;
// 'useEffect' 用于在函数组件中执行副作用操作,比如发起网络请求、订阅数据更新、操作 DOM 等,在这里用于在组件的不同阶段执行获取聊天会话数据等相关操作。
import Chat from './Chat';
// 导入同目录下自定义的 'Chat' 组件,这个组件应该是用于展示具体的聊天对话内容的,接收相应的属性(比如聊天对象名称等)来呈现对应的聊天消息记录,实现具体的聊天界面功能。
import './Style/Session.less';
// 导入相对路径 './Style/Session.less' 对应的样式文件(这里假设是使用了 CSS 预处理器 LESS 编写的样式文件),用于给当前组件应用相应的自定义样式,实现聊天列表、卡片等元素特定的外观设计,如设置滚动条样式、内外边距等。
const {Text} = Typography;
// 通过解构赋值从 'Typography' 组件中获取 'Text' 组件,'Text' 组件通常用于在页面上展示普通文本内容,并且可以应用一些额外的样式控制,比如这里用于在展示会话标题、消息摘要以及时间等文本时设置省略显示等样式效果,使文本展示更加灵活、美观。
export default () => {
// 定义一个默认导出的匿名函数式组件,这个组件是整个聊天相关功能界面的核心,负责构建聊天列表展示以及与具体聊天对话交互的整体布局和功能逻辑。
const [isSessionLoading, setIsSessionLoading] = useState(false);
// 使用 'useState' hook 创建一个名为 'isSessionLoading' 的状态变量,初始值设为 false用于表示当前是否正在加载聊天会话数据的状态
// 当发起获取会话数据请求时,会将其设置为 true加载完成后再变回 false方便在界面上展示相应的数据加载提示效果例如在聊天列表处显示加载动画等。
const [sessionList, setSessionList] = useState<SessionItem[]>([]);
// 同样使用 'useState' hook 创建'sessionList' 这个状态变量,初始值设为一个空数组,其类型被定义为 'SessionItem' 类型的数组('SessionItem' 类型应该在其他地方定义),
// 这个状态变量用于存储从服务器获取到的聊天会话列表相关的数据,后续会根据实际获取的数据进行更新,以便在聊天列表中展示各个会话的详细信息。
const [userName, setUserName] = useState<string>();
// 再次使用 'useState' hook 创建 'userName' 状态变量,初始值设为 undefined因为类型定义为字符串类型这里默认就是 undefined
// 它用于存储当前点击选中的聊天对象的用户名,当用户点击聊天列表中的某个会话项时,会更新这个状态变量,进而影响后续相关界面元素的展示以及与具体聊天组件的交互逻辑。
const [nickName, setNickName] = useState<string>();
// 继续使用 'useState' hook 创建 'nickName' 状态变量,初始值设为 undefined同理类型为字符串类型默认就是 undefined
// 这个状态变量用于存储当前点击选中的聊天对象的昵称,作用与 'userName' 类似,不过侧重于展示聊天对象更友好、易读的名称信息,会根据用户的操作进行相应更新,用于界面上相应位置的展示。
const getSession = async () => {
// 定义一个名为 'getSession' 的异步函数,其主要作用是获取聊天会话列表数据。
try {
setIsSessionLoading(true);
// 在准备发起获取聊天会话数据的请求之前,先将 'isSessionLoading' 状态变量的值设置为 true告知用户当前正在进行数据加载操作界面上可据此展示相应的加载提示元素比如在聊天列表处显示加载动画。
const response = await querySession();
// 调用之前导入的 'querySession' 函数,它返回一个 Promise通过 'await' 等待这个 Promise 被成功 resolve即请求完成并返回数据
// 将返回的结果赋值给'response' 变量,这里的结果应该包含了获取聊天会话列表操作的相关信息,比如是否成功获取以及具体的会话数据等。
setSessionList(response.data);
// 从'response' 变量中取出 'data' 属性(假设服务器返回的数据结构中有 'data' 字段存放实际的会话列表内容),
// 再使用'setSessionList' 函数更新'sessionList' 状态变量,这样组件会根据新的会话列表数据重新渲染,进而在聊天列表中展示出最新的会话信息。
} catch (error) {
console.error(error);
// 如果在请求聊天会话列表的过程中出现错误,比如网络连接问题、服务器返回错误等,通过 'console.error' 把错误信息打印到控制台,便于进行调试和错误排查。
}
setIsSessionLoading(false);
// 不管是否成功获取到聊天会话列表数据,最后都要把 'isSessionLoading' 状态变量的值重新设置为 false表示数据加载操作已经结束相应地可以隐藏界面上的加载提示元素比如停止聊天列表处的加载动画显示。
};
const handleMsg = (item: SessionItem) => {
// 定义一个名为 'handleMsg' 的函数,接收一个 'SessionItem' 类型的参数 'item'(代表聊天会话列表中的一个会话项对象),用于处理用户点击聊天会话项时的操作逻辑。
setUserName(item.userName);
// 将点击的会话项对象中的 'userName' 属性值取出,使用'setUserName' 函数更新 'userName' 状态变量,这样组件就能知道当前选中的聊天对象的用户名,便于后续与具体聊天组件进行交互以及相关界面展示。
setNickName(item.nickName);
// 同样地,将点击的会话项对象中的 'nickName' 属性值取出,使用'setNickName' 函数更新 'nickName' 状态变量,用于在界面上合适的位置(比如聊天窗口标题处等)展示聊天对象的昵称信息。
};
useEffect(() => {
getSession();
}, []);
// 使用 'useEffect' hook传入一个回调函数这里是调用 'getSession' 函数来获取聊天会话列表)和一个空的依赖项数组 []。
// 空的依赖项数组意味着这个副作用操作(获取聊天会话列表)只会在组件初次挂载时执行一次,即组件加载完成后会立即发起获取聊天会话列表的请求,获取到数据后用于后续的聊天列表构建以及相关交互操作逻辑处理。
return (
<ProCard split="vertical">
// 返回一个 'ProCard' 组件,设置'split' 属性为 "vertical",表示以垂直方向分割卡片样式,可能用于划分不同的功能区域,构建出具有层次感的界面布局效果,这里整体作为聊天功能界面的最外层容器。
<ProCard bordered title="聊天列表" colSpan="28%" bodyStyle={{paddingInline: '0px'}}>
// 在外层 'ProCard' 组件内部,嵌套另一个 'ProCard' 组件用于专门展示聊天列表,设置 'bordered' 属性为 true 使其显示边框,更清晰地划分出聊天列表区域,
// 'title' 属性设置为 "聊天列表",直观地告知用户这个区域展示的内容主题,'colSpan' 属性设置为 "28%",可能用于控制该卡片在水平方向上占据的宽度比例,使其与其他区域(比如具体聊天窗口区域)合理分配空间,
// 'bodyStyle' 属性通过传入一个对象设置卡片主体内容区域的样式,这里将内联方向(水平方向)的内边距设置为 0 像素('paddingInline: '0px''),避免出现不必要的空白区域,使聊天列表能充分利用空间展示内容。
<List
dataSource={sessionList}
className="session-scrollbar"
@ -43,7 +89,7 @@ export default () => {
renderItem={(item) => (
<List.Item
onClick={() => handleMsg(item)}
className={`sessionItem ${item.userName === userName ? 'highlighted' : ''}`}
className={`sessionItem ${item.userName === userName? 'highlighted' : ''}`}
>
<List.Item.Meta
avatar={<Avatar src={item.headImgUrl}/>}
@ -54,15 +100,30 @@ export default () => {
</List.Item>
)}
/>
// 在这个用于展示聊天列表的 'ProCard' 组件内部,使用 'List' 组件来展示具体的聊天会话列表信息,设置 'dataSource' 属性绑定'sessionList' 状态变量,将获取到的聊天会话列表数据作为数据源,
// 'className' 属性设置为 "session-scrollbar",用于应用对应的样式类(来自之前导入的样式文件)来定义聊天列表的滚动条等外观样式,方便用户查看较多的会话信息,
// 'loading' 属性根据 'isSessionLoading' 状态变量来决定列表是否显示加载状态(比如显示加载动画等),通过'renderItem' 函数来渲染每个会话列表项,对于每个会话项('item'
// - 为其绑定 'onClick' 点击事件处理函数,当用户点击会话项时,会调用 'handleMsg' 函数并传入当前会话项对象,实现记录当前选中的聊天对象信息等操作逻辑;
// - 设置 'className' 属性,通过一个三元表达式判断当前会话项的用户名('item.userName')是否与当前选中的聊天对象用户名('userName' 状态变量)相等,
// 如果相等则添加 'highlighted' 样式类(这个样式类应该在样式文件中定义了相应的突出显示效果,比如改变背景颜色等),用于在界面上突出显示当前选中的会话项,方便用户直观地看到当前选择的是哪个聊天对象;
// - 在每个会话项内部,使用 'List.Item.Meta' 组件来设置会话项的元数据信息,包括通过 'avatar' 属性设置会话项的头像,传入一个 'Avatar' 组件并绑定对应的头像图片链接('item.headImgUrl')来展示聊天对象的头像,
// 通过 'title' 属性设置会话项的标题,传入一个 'Text' 组件并展示聊天对象的昵称('item.nickName'),同时应用省略显示样式('ellipsis')防止昵称过长溢出,
// 通过 'description' 属性设置会话项的描述信息,传入一个 'Text' 组件并展示会话项对应的最近消息内容('item.content'),同样应用省略显示样式,方便展示简短的消息摘要;
// - 最后,在会话项内部还展示一个 'Text' 组件,设置 'className' 属性为 "timeText"(对应的样式类应该定义了时间文本的相关样式,比如字体颜色、大小等),用于展示会话项对应的时间信息('item.shortTime'),让用户了解会话的时间情况。
</ProCard>
<ProCard
bordered
title={nickName ? nickName : '~'}
title={nickName? nickName : '~'}
headerBordered
bodyStyle={{paddingInline: '0px'}}
>
<Chat userName={userName}/>
</ProCard>
// 在外层 'ProCard' 组件内,除了聊天列表的 'ProCard' 组件外,还嵌套另一个 'ProCard' 组件用于展示具体的聊天对话内容,设置 'bordered' 属性为 true 使其显示边框,
// 'title' 属性通过一个三元表达式设置为当前选中的聊天对象的昵称('nickName' 状态变量,如果有值则显示昵称,否则显示 '~'),用于直观地告知用户当前正在与谁聊天,
// 'headerBordered' 属性设置为 true可能用于给卡片头部标题区域添加边框等样式效果使其与主体内容区域有更清晰的划分
// 'bodyStyle' 属性同样将内联方向(水平方向)的内边距设置为 0 像素,确保聊天内容展示区域能充分利用空间,
// 在这个 'ProCard' 组件内部,使用之前导入的 'Chat' 组件来展示具体的聊天对话内容,传入 'userName' 状态变量作为属性,使 'Chat' 组件能根据聊天对象的用户名获取并展示对应的聊天消息记录,实现具体的聊天功能。
</ProCard>
);
};

@ -1,17 +1,23 @@
.chat-scrollbar {
height: 650px;
/* 设置元素的高度为 650 像素,这个元素可能是聊天内容展示区域等,用于限制其垂直方向上占据的空间大小。 */
overflow-y: auto;
/* 当内容在垂直方向y 轴上超出设定的高度650px会自动出现滚动条方便用户查看超出部分的内容。 */
&::-webkit-scrollbar {
width: 3px;
/* 针对基于 WebKit 内核浏览器(如 Chrome、Safari 等)中的滚动条,设置其宽度为 3 像素,定义滚动条在水平方向上的尺寸大小,使滚动条看起来更纤细或符合特定设计风格。 */
}
&::-webkit-scrollbar-thumb {
background-color: #888;
/* 设置 WebKit 内核浏览器中滚动条滑块(可拖动部分)的背景颜色为深灰色(#888定义了其默认的外观颜色。 */
border-radius: 5px;
/* 给滚动条滑块设置圆角效果,圆角半径为 5 像素,让滑块的边角看起来更圆润,提升视觉美观度。 */
&:hover {
background-color: #555;
/* 当鼠标悬停在滚动条滑块上时,改变其背景颜色为更暗一点的灰色(#555通过这种交互效果增强视觉反馈提示用户可以进行拖动操作等。 */
}
}
}
@ -19,67 +25,87 @@
.more-msg {
margin-top: 5px;
margin-bottom: 5px;
/* 分别设置元素的上外边距和下外边距为 5 像素,用于控制该元素与相邻元素在垂直方向上的间距,使其在页面布局中位置更合理,看起来更协调。 */
text-align: center;
/* 使元素内部的文本内容居中对齐,常用于提示信息、按钮等元素,让文本显示更加整齐、美观,符合常见的页面排版习惯。 */
}
.msg-item {
margin-top: 25px;
margin-bottom: 25px;
/* 给消息项msg-item元素设置上下外边距为 25 像素,用于区分不同的消息项,在聊天记录列表中使每条消息之间有一定的间隔,方便用户查看和区分不同消息。 */
&.sender {
justify-content: flex-end;
/* 当消息项msg-item元素同时具有'sender' 类名时(可能表示这条消息是发送方发出的),使用 flex 布局并将其内容在水平方向上靠右对齐,符合通常聊天界面中发送消息靠右显示的习惯。 */
.msg-content {
flex-direction: row-reverse;
/* 对于发送方消息项中的'msg-content' 子元素,设置其 flex 布局的方向为反向的行方向(从右往左排列),可能用于调整消息内容(比如文本、图片等)在发送方消息框内的排列顺序,使其符合视觉和交互逻辑。 */
}
}
&.receiver {
justify-content: flex-start;
/* 当消息项msg-item元素同时具有'receiver' 类名时(可能表示这条消息是接收方收到的),使用 flex 布局并将其内容在水平方向上靠左对齐,符合聊天界面中接收消息靠左显示的常规设计。 */
.msg-content {
flex-direction: row;
/* 对于接收方消息项中的'msg-content' 子元素,设置其 flex 布局的方向为正常的行方向(从左往右排列),以合理排列接收方消息框内的内容,使其符合视觉和交互逻辑。 */
}
}
}
.msg-system {
margin-top: 16px;
/* 设置系统消息msg-system元素的上外边距为 16 像素,用于将系统消息与其他消息或元素在垂直方向上拉开一定距离,使其更易区分和查看。 */
}
.msg-system-text {
max-width: 500px;
/* 设置系统消息文本msg-system-text元素的最大宽度为 500 像素,限制文本内容在水平方向上的展示宽度,避免文本过长影响页面布局美观度,同时也便于阅读。 */
font-size: 12px;
/* 设置系统消息文本的字体大小为 12 像素,使其显示相对较小,符合系统消息通常作为辅助提示信息、不太突出显示的特点。 */
}
.message-text {
max-width: 400px;
/* 设置普通消息文本message-text元素的最大宽度为 400 像素,同样是为了限制消息内容在水平方向上的展示宽度,确保消息框大小合适,页面布局整齐。 */
padding: 10px;
/* 给消息文本元素设置内边距为 10 像素,在消息文本内容四周添加一定空白空间,使其在消息框内显示更加美观、舒适,不会显得过于拥挤。 */
border-radius: 10px;
/* 给消息文本元素设置圆角效果,圆角半径为 10 像素,使消息框的边角看起来更圆润,提升整体视觉美观度,符合常见的消息框样式风格。 */
&.sender {
background-color: #b9fb97;
/* 当消息文本message-text元素同时具有'sender' 类名(即发送方消息)时,设置其背景颜色为淡绿色(#b9fb97用于区分发送方和接收方消息通过颜色直观地体现消息来源。 */
}
&.receiver {
background-color: #eff2f2;
/* 当消息文本message-text元素同时具有'receiver' 类名(即接收方消息)时,设置其背景颜色为淡灰色(#eff2f2与发送方消息的背景颜色形成对比方便用户快速区分不同来源的消息。 */
}
}
.msg-card-link {
width: 400px;
/* 设置消息卡片链接msg-card-link元素的宽度为 400 像素,用于控制该元素在页面水平方向上占据的空间大小,可能是针对某种特定的消息卡片样式,比如图片、链接卡片等,使其展示尺寸符合设计要求。 */
}
.msg-we-app-info {
width: 200px;
/* 设置微信小程序相关信息msg-we-app-info元素的宽度为 200 像素,限定其水平方向的尺寸,用于在聊天界面中合理展示小程序相关的介绍、图标等信息,使其布局更紧凑、美观。 */
}
.refer-msg-content {
max-width: 400px;
/* 设置引用消息内容refer-msg-content元素的最大宽度为 400 像素,限制引用消息在水平方向的展示宽度,避免其过长影响页面布局和阅读体验。 */
margin-top: 5px;
/* 设置引用消息内容元素的上外边距为 5 像素,使其与上方的元素在垂直方向上有一定间隔,更易区分和查看。 */
}
.msg-avatar {
margin-right: 15px;
margin-left: 15px;
/* 给消息头像msg-avatar元素设置左右外边距为 15 像素,用于控制头像与相邻元素(比如消息文本等)在水平方向上的间距,使其在聊天界面中位置更合理,布局更协调美观。 */
}

@ -1,34 +1,47 @@
.session-scrollbar {
height: 675px;
/* 设置该元素的高度为 675 像素,此元素可能是用于展示会话相关内容的容器,限制其在垂直方向上占据的空间大小,超出这个高度的内容可以通过滚动条查看。 */
overflow-y: auto;
/* 当会话内容在垂直方向y 轴)超出设定的 675 像素高度时,自动显示垂直滚动条,方便用户上下滚动查看所有的会话信息,实现内容的可滚动浏览效果。 */
&::-webkit-scrollbar {
width: 3px;
/* 针对基于 WebKit 内核浏览器(如 Chrome、Safari 等)中的滚动条,设置其宽度为 3 像素,定义滚动条在水平方向上的尺寸大小,使其外观更符合特定的设计风格,一般较窄的滚动条看起来会更精致一些。 */
}
&::-webkit-scrollbar-thumb {
background-color: #888;
/* 设定 WebKit 内核浏览器中滚动条滑块(也就是滚动条上可拖动的部分)的背景颜色为深灰色(#888用于定义滚动条滑块默认的外观颜色。 */
border-radius: 5px;
/* 给滚动条滑块添加圆角效果,圆角半径为 5 像素,让滑块的边角变得圆润,提升整体的视觉美观度,使滚动条看起来更加柔和、美观。 */
&:hover {
background-color: #555;
/* 当鼠标悬停在滚动条滑块上时,改变其背景颜色为更暗一点的灰色(#555通过这种交互效果增强视觉反馈提示用户可以进行拖动操作同时也能让用户更清晰地感知到鼠标所在位置与滚动条的交互状态。 */
}
}
.sessionItem {
display: flex;
/* 将具有'sessionItem' 类名的元素设置为弹性布局flex layout弹性布局可以方便地对其内部子元素进行排列和对齐操作使其布局更加灵活、高效。 */
align-items: baseline;
/* 在弹性布局下,使'sessionItem' 元素内部的子元素在垂直方向上按照基线baseline对齐保证不同行内元素的文本基线是对齐的让布局看起来更加整齐、规范。 */
justify-content: space-between;
/* 在弹性布局下,让'sessionItem' 元素内部的子元素在水平方向上均匀分布,两端对齐,常用于将标题、内容和操作按钮等元素在一行内合理分布,使得布局空间利用更合理,元素之间间距均匀。 */
padding-right: 15px;
padding-left: 15px;
/* 分别给'sessionItem' 元素的右侧和左侧添加 15 像素的内边距,在元素内部内容与边界之间留出一定的空白空间,使其看起来不会过于拥挤,布局更加舒适、美观。 */
&.highlighted {
background-color: #f0f0f0;
/* 当'sessionItem' 元素同时具有 'highlighted' 类名时(可能表示该会话项处于被选中、高亮等特殊状态),设置其背景颜色为浅灰色(#f0f0f0通过改变背景颜色来突出显示该会话项方便用户区分和关注。 */
}
}
.timeText {
color: gray;
/* 设置具有 'timeText' 类名的元素文本颜色为灰色,通常用于表示时间相关文本,使其与其他主要内容文本颜色有所区分,更符合时间信息作为辅助说明的特点。 */
font-size: 13px;
/* 设置 'timeText' 元素的字体大小为 13 像素,让时间文本显示的字号相对较小,进一步体现其作为辅助信息的定位,同时也与整体页面的排版风格相协调。 */
}
}

@ -1,41 +1,69 @@
.topContactList {
margin: 25px 0 0;
/* 设置外边距,上外边距为 25 像素,左右外边距为 0下外边距为 0用于控制该列表与上方元素的距离使其在页面中垂直方向上有合适的间隔布局更合理。 */
padding: 0;
/* 将内边距设置为 0清除列表默认的内边距使列表项能从最边缘开始布局避免出现不必要的空白区域符合特定的设计要求。 */
list-style: none;
/* 去除列表默认的项目符号(比如小圆点等),让列表呈现更简洁的外观,通常在自定义列表样式时会进行这样的设置。 */
li {
display: flex;
/* 将列表项li设置为弹性布局flex layout方便对其内部的子元素进行灵活的排列和对齐操作更易于实现复杂且整齐的布局效果。 */
align-items: center;
/* 在弹性布局下,使列表项内的子元素在垂直方向上居中对齐,确保各个子元素在垂直方向上处于同一水平线上,视觉上更加整齐、美观。 */
margin-top: 20px;
/* 给每个列表项设置上外边距为 20 像素,用于区分不同的列表项,使列表中的各个项之间有一定的间隔,方便查看和区分不同的联系人信息。 */
zoom: 1;
/* 这个属性在一些旧版本浏览器(如早期的 Internet Explorer中用于触发元素的 hasLayout 属性,以解决一些布局相关的兼容性问题,不过在现代浏览器中作用不大,但可能是为了保持一定的兼容性而保留的设置。 */
span {
color: @text-color;
/* 设置所有 <span> 元素的文本颜色为 @text-color这里 @text-color 应该是一个预定义的变量(可能通过 CSS 预处理器定义,如 LESS、SASS 等),用于统一文本颜色,方便整体样式的主题切换等操作。 */
font-size: 14px;
/* 设置 <span> 元素的字体大小为 14 像素,确定文本显示的字号大小,使其符合整体页面的文字排版风格。 */
line-height: 22px;
/* 设置行高为 22 像素,行高影响文本行之间的垂直间距,合适的行高可以让文本看起来更舒适、易读,提升阅读体验。 */
}
.topContactItemNumber {
display: inline-block;
/* 将具有 '.topContactItemNumber' 类名的元素设置为内联块级元素,它既有内联元素可以与其他文本元素同行显示的特点,又具备块级元素可以设置宽高、内外边距等属性的特性,方便进行布局和样式设置。 */
width: 20px;
/* 设置元素的宽度为 20 像素,用于确定该元素在水平方向上占据的空间大小,可能用于展示联系人的序号等内容,使其有固定的宽度显示更整齐。 */
height: 20px;
/* 设置元素的高度为 20 像素,与宽度配合确定元素的尺寸,使其呈现为一个方形的小区域,符合常见的序号等展示元素的形状特点。 */
margin-top: 1.5px;
/* 给元素设置上外边距为 1.5 像素,微调元素在垂直方向上的位置,使其与相邻元素的对齐更加精准、美观。 */
margin-right: 16px;
/* 设置元素的右外边距为 16 像素,用于控制该元素与右侧相邻元素之间的间隔,使布局更合理,元素之间不会过于拥挤。 */
font-weight: 600;
/* 设置字体粗细为 600使文本看起来更加粗重一些常用于突出显示重要信息比如这里可能用于让联系人序号更醒目。 */
font-size: 12px;
/* 设置该元素内文本的字体大小为 12 像素,使其字号相对较小,与其他文本有所区分,同时又能清晰展示序号内容。 */
line-height: 20px;
/* 设置该元素内文本的行高为 20 像素,确保文本在这个小区域内垂直方向上的排版合适,显示更整齐。 */
text-align: center;
/* 使元素内的文本在水平方向上居中对齐,保证序号等文本在设定的方形区域内水平居中显示,更加美观、整齐。 */
background-color: @tag-default-bg;
/* 设置元素的背景颜色为 @tag-default-bg同样这里 @tag-default-bg 应该是一个预定义的变量,用于统一设置这类元素的背景颜色,方便样式的整体管理和主题切换。 */
border-radius: 20px;
/* 给元素设置圆角效果,圆角半径为 20 像素,使其四个角都呈现为圆形,整体外观更加圆润、美观,符合一些现代 UI 设计风格。 */
&.active {
color: #fff;
/* 当元素同时具有 '.active' 类名时(可能表示处于某种活跃、选中或特殊状态),设置文本颜色为白色(#fff改变文本颜色以突出显示该状态下的元素增强视觉效果。 */
background-color: #314659;
/* 同时将背景颜色设置为 #314659改变背景颜色来进一步强调该元素处于特殊状态与默认状态形成明显对比方便用户识别和区分。 */
}
}
.topContactItemTitle {
flex: 1;
/* 在弹性布局下,设置该元素占据剩余的所有可用空间,使其可以自适应地填充剩余空间,常用于文本内容区域,保证文本能充分利用空间展示,同时也方便其他元素根据其自动调整位置。 */
padding-left: 15px;
/* 给元素左侧添加 15 像素的内边距,使文本内容与左侧相邻元素之间有一定的空白间隔,看起来更加舒适、美观,避免文本过于贴近其他元素。 */
overflow: hidden;
/* 当文本内容超出元素的宽度时,隐藏超出部分的内容,防止文本溢出导致布局混乱,保证界面的整洁性。 */
white-space: nowrap;
/* 强制文本在一行内显示,不进行换行,配合 'overflow: hidden' 属性,实现文本超出宽度时以省略号显示的效果(通过 'text-overflow: ellipsis' 一起作用)。 */
text-overflow: ellipsis;
/* 当文本溢出元素宽度时,在末尾显示省略号(...)来表示文本被截断了,常用于展示较长的文本标题等内容,既能展示关键信息,又能保证布局不受长文本影响。 */
}
}
}

@ -1,80 +1,141 @@
import { InfoCircleOutlined, UserSwitchOutlined } from '@ant-design/icons';
import { Dropdown, Avatar, message, Modal, Descriptions,Typography } from 'antd';
// 从 Ant Design 的图标库中导入两个图标组件,'InfoCircleOutlined' 图标通常用于表示信息提示相关的功能,'UserSwitchOutlined' 图标则用于体现用户切换相关的操作,
// 这些图标将用于构建界面上相应功能的可视化标识,提升用户交互的直观性。
import { Dropdown, Avatar, message, Modal, Descriptions, Typography } from 'antd';
// 从 Ant Design'antd')库中导入多个组件,包括用于创建下拉菜单的 'Dropdown' 组件、展示用户头像的 'Avatar' 组件、显示提示消息的'message' 组件、弹出模态框的 'Modal' 组件、
// 以键值对形式展示描述信息的 'Descriptions' 组件以及处理文本相关展示的 'Typography'(后续还从中解构出了 'Text' 组件用于更精细的文本展示控制),这些组件共同协作来构建整个用户切换与信息展示的界面功能。
import type { MenuProps } from 'antd';
// 导入 Ant Design 中菜单组件Menu相关的属性类型定义'MenuProps'),用于后续准确地定义和约束下拉菜单的相关属性及事件处理函数的类型,确保类型安全以及符合 Ant Design 组件的使用规范。
import React, { useState, useEffect } from 'react';
import { getUsers, switchUser,getUserInfo } from "@/services/User";
// 导入 React 框架以及两个常用的 React hooks'useState' 和 'useEffect'。
// 'useState' 用于在函数组件里定义和管理状态,使得组件能够根据状态的变化重新渲染,展示不同的界面内容;
// 'useEffect' 用于在函数组件中执行副作用操作,比如发起网络请求、订阅数据更新、操作 DOM 等,在这里用于在组件的不同阶段执行诸如获取用户数据等操作。
import { getUsers, switchUser, getUserInfo } from "@/services/User";
// 从项目中相对路径为 '@/services/User' 的模块里导入三个函数,分别是 'getUsers'(推测其功能是向服务器端发起请求获取用户列表信息)、'switchUser'(可能用于向服务器发送切换用户的请求操作)、
// 'getUserInfo'(大概率是用于获取当前用户的详细账号信息),这些函数将用于与后端进行交互,获取相应的数据来支持前端界面的功能展示与操作逻辑实现。
export type SwitchUserProps = {
children?: React.ReactNode;
};
// 定义一个名为 'SwitchUserProps' 的接口类型,用于描述传递给 'SwitchUser' 组件的属性类型,这里只定义了一个可选的 'children' 属性,其类型为 React 节点(可以是 React 元素、文本、数组等任意合法的 React 内容),
// 意味着这个组件可以接收子元素,并且在组件内部可以根据需要进行相应的渲染处理,具有一定的灵活性和扩展性。
const SwitchUser: React.FC<SwitchUserProps> = ({ children }) => {
// 定义一个名为 'SwitchUser' 的函数式组件,遵循 React.FCFunction Component类型定义接收一个符合 'SwitchUserProps' 接口类型的属性对象(在这里就是接收 'children' 属性),
// 此组件主要用于实现用户切换以及账号信息查看等相关功能,构建对应的用户交互界面。
const [users, setUsers] = useState<UserItem[]>([]);
// 使用 'useState' hook 创建一个名为 'users' 的状态变量,初始值设为一个空数组,其类型被定义为 'UserItem' 类型的数组('UserItem' 类型应该在其他地方定义),
// 这个状态变量用于存储从服务器获取到的用户列表相关的数据,后续会根据实际获取的数据进行更新,以便在下拉菜单等界面元素中展示不同的用户选项供切换操作使用。
const [userInfo, setUserInfo] = useState<UserInfo>();
// 同样使用 'useState' hook 创建 'userInfo' 这个状态变量,初始值设为 undefined因为类型定义为 'UserInfo' 类型,这里默认就是 undefined
// 它用于存储从服务器获取到的当前用户的详细账号信息,一旦获取到相应数据,组件会根据其重新渲染,在模态框中展示出具体的账号信息内容,如微信 ID、昵称等。
const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
// 再次使用 'useState' hook 创建'selectedKeys' 状态变量,初始值设为一个空数组,类型为字符串数组,这个变量用于记录当前在下拉菜单中被选中的用户对应的键值(通常是用户的唯一标识,比如微信 ID 等),
// 方便在界面上显示当前选中状态以及进行后续的相关操作判断等。
const [isModalOpen, setIsModalOpen] = useState(false);
// 继续使用 'useState' hook 创建 'isModalOpen' 状态变量,初始值设为 false用于表示是否打开账号信息展示的模态框当需要展示账号信息时将其设置为 true关闭时再设置回 false
// 通过这个状态来控制模态框在界面上的显示与隐藏,实现交互效果。
const { Text } = Typography;
// 通过解构赋值从 'Typography' 组件中获取 'Text' 组件,'Text' 组件通常用于在页面上展示普通文本内容,并且可以应用一些额外的样式控制,比如这里用于在展示账号信息时设置文本的省略显示等样式效果,使文本展示更加灵活、美观。
const handleUserInfoOk = () => {
setIsModalOpen(false);
};
// 定义一个名为 'handleUserInfoOk' 的函数,用于处理账号信息模态框中点击确定按钮的操作,其功能就是将 'isModalOpen' 状态变量设置为 false从而关闭模态框隐藏账号信息展示界面。
const handleUserInfoCancel = () => {
setIsModalOpen(false);
};
// 定义一个名为 'handleUserInfoCancel' 的函数,用于处理账号信息模态框中点击取消按钮的操作,同样也是将 'isModalOpen' 状态变量设置为 false达到关闭模态框的目的
// 这两个函数分别绑定到模态框对应的按钮点击事件上,实现了对模态框显示与隐藏的控制。
const handleUsers = async () => {
// 定义一个名为 'handleUsers' 的异步函数,其主要作用是获取用户列表信息。
try {
const response = await getUsers();
// 调用之前导入的 'getUsers' 函数,它返回一个 Promise通过 'await' 等待这个 Promise 被成功 resolve即请求完成并返回数据
// 将返回的结果赋值给'response' 变量,这里的结果应该包含了获取用户列表操作的相关信息,比如是否成功获取以及具体的用户数据等。
if (response.success) {
setUsers(response.data);
// 如果服务器返回的结果中'success' 属性为 true也就是成功获取到了用户列表数据那么就从'response' 变量中取出 'data' 属性(假设服务器返回的数据结构中有 'data' 字段存放实际的用户列表内容),
// 再使用'setUsers' 函数更新 'users' 状态变量,这样组件会根据新的用户列表数据重新渲染,进而在下拉菜单等界面元素中展示出最新的用户选项。
const currentUser = response.data.find((user: UserItem) => user.current);
// 在获取到的用户列表数据中查找当前登录用户(通过判断每个用户对象中的 'current' 属性是否为 true这里假设存在这样的标识来区分当前用户将找到的当前用户对象赋值给 'currentUser' 变量。
if (currentUser) {
setSelectedKeys([currentUser.wxId]);
// 如果找到了当前用户,就从当前用户对象中取出微信 ID'wxId' 属性),并将其作为一个元素组成的数组,使用'setSelectedKeys' 函数更新'selectedKeys' 状态变量,
// 这样在下拉菜单中就能正确显示当前用户处于选中状态,方便用户直观地看到当前所处的用户账号情况。
}
}
} catch (error) {
console.error(error);
// 如果在请求用户列表的过程中出现错误,比如网络连接问题、服务器返回错误等,通过 'console.error' 把错误信息打印到控制台,便于进行调试和错误排查。
}
};
const handleUserInfo = async () => {
// 定义一个名为 'handleUserInfo' 的异步函数,其主要功能是获取当前用户的详细账号信息。
try {
const response = await getUserInfo();
// 调用之前导入的 'getUserInfo' 函数,它返回一个 Promise通过 'await' 等待这个 Promise 被成功 resolve即请求完成并返回数据
// 将返回的结果赋值给'response' 变量,这里的结果应该包含了获取当前用户账号信息操作的相关信息,比如是否成功获取以及具体的账号信息内容等。
if (response.success) {
setUserInfo(response.data);
// 如果服务器返回的结果中'success' 属性为 true也就是成功获取到了账号信息数据那么就从'response' 变量中取出 'data' 属性(假设服务器返回的数据结构中有 'data' 字段存放实际的账号信息内容),
// 再使用'setUserInfo' 函数更新 'userInfo' 状态变量,这样组件会根据新的账号信息数据重新渲染,进而在模态框中展示出最新的、准确的账号信息内容。
}
} catch (error) {
console.error(error);
// 如果在请求用户账号信息的过程中出现错误,比如网络连接问题、服务器返回错误等,通过 'console.error' 把错误信息打印到控制台,便于进行调试和错误排查。
}
};
useEffect(() => {
handleUsers();
}, []);
// 使用 'useEffect' hook传入一个回调函数这里是调用 'handleUsers' 函数来获取用户列表)和一个空的依赖项数组 []。
// 空的依赖项数组意味着这个副作用操作(获取用户列表)只会在组件初次挂载时执行一次,即组件加载完成后会立即发起获取用户列表的请求,获取到数据后用于后续的下拉菜单等界面元素构建以及相关操作逻辑处理。
const onClick: MenuProps['onClick'] = async ({ key }) => {
// 定义一个名为 'onClick' 的异步函数,其类型符合 Ant Design 菜单组件Menu的点击事件处理函数类型'MenuProps['onClick']'),接收一个包含点击菜单项的键值('key')信息的对象参数,
// 用于处理下拉菜单中各项被点击时的操作逻辑。
const selectKey = `${key}`;
// 将点击菜单项的键值('key')转换为字符串类型,并赋值给'selectKey' 变量,方便后续进行字符串类型的比较和逻辑判断操作。
if (selectKey == 'switch') {
return;
// 如果点击的菜单项键值为'switch',表示点击的是“切换账号”这一顶层菜单选项(但还未选择具体的用户),这里直接返回不做其他操作,可能后续可以在此添加展开下拉菜单等更复杂的逻辑。
}
if (selectKey == 'userInfo') {
setIsModalOpen(true);
handleUserInfo();
return;
// 如果点击的菜单项键值为 'userInfo',表示点击的是“账号信息”这一菜单选项,此时先将 'isModalOpen' 状态变量设置为 true打开账号信息展示的模态框
// 然后调用 'handleUserInfo' 函数去获取当前用户的详细账号信息,以便在模态框中展示出来,之后直接返回,结束此次点击事件处理逻辑。
}
try {
const response = await switchUser({ wxId: selectKey });
// 如果点击的菜单项键值既不是'switch' 也不是 'userInfo',则认为是点击了具体的用户选项(以用户的微信 ID 等作为键值),尝试调用'switchUser' 函数发起切换用户的请求,
// 传入一个包含要切换到的用户微信 ID'wxId')的对象作为参数,它返回一个 Promise等待这个 Promise 被成功 resolve即请求完成并返回数据将返回的结果赋值给'response' 变量,这里的结果应该包含了切换用户操作的相关信息,比如是否成功切换等。
if (response.success) {
window.location.reload();
// 如果服务器返回的结果中'success' 属性为 true也就是成功切换了用户那么通过 'window.location.reload()' 方法刷新整个页面,使页面以新切换的用户身份重新加载,展示相应的界面和数据。
}
} catch (error) {
console.error(error);
message.error('切换用户失败,请稍后重试。');
// 如果在切换用户的过程中出现错误,比如网络连接问题、服务器返回错误等,先通过 'console.error' 把错误信息打印到控制台,便于进行调试和错误排查,
// 然后使用 Ant Design 的'message' 组件的 'error' 方法弹出一个错误提示消息,告知用户“切换用户失败,请稍后重试。”,提升用户体验,让用户知晓操作出现了问题。
}
};
@ -83,6 +144,11 @@ const SwitchUser: React.FC<SwitchUserProps> = ({ children }) => {
label: user.nickname,
icon: <Avatar shape="square" size={20} src={user.avatar} />,
}));
// 通过对 'users' 状态变量(存储的用户列表数据)进行'map' 操作,为每个用户创建一个对应的菜单项对象,包含三个属性:
// 'key' 属性设置为用户的微信 ID'wxId'),用于唯一标识每个菜单项以及后续的操作判断等;
// 'label' 属性设置为用户的昵称('nickname'),用于在下拉菜单中直观地展示用户的名称信息,方便用户识别;
// 'icon' 属性设置为一个 'Avatar' 组件,通过传入用户的头像链接('avatar')以及设置形状('square')和尺寸('size' 为 20在菜单项前面展示用户的头像图标使菜单更加美观、直观方便用户区分不同用户。
// 最终将这些菜单项对象组成的数组赋值给 'userMenuItems' 变量,用于构建下拉菜单中的用户选项部分。
const menuItems = [
{
@ -102,12 +168,22 @@ const SwitchUser: React.FC<SwitchUserProps> = ({ children }) => {
label: '账号信息',
},
];
// 构建整个下拉菜单的菜单项配置数组'menuItems',包含三个主要部分:
// 第一部分是一个表示“切换账号”的顶层菜单项,设置 'key' 为'switch',图标为 '<UserSwitchOutlined />',标签为“切换账号”,其 'children' 属性包含了之前构建的所有用户选项菜单项('userMenuItems'
// 这样点击“切换账号”时会展开下拉菜单展示具体的用户列表供选择切换;
// 第二部分是一个类型为 'divider'(通过 'as const' 明确类型为常量的分隔线类型)的元素,用于在菜单中添加一条水平分隔线,将“切换账号”和“账号信息”两个功能选项在视觉上进行区分,使菜单结构更清晰;
// 第三部分是一个表示“账号信息”的菜单项,设置 'key' 为 'userInfo',图标为 '<InfoCircleOutlined />',标签为“账号信息”,点击它会打开模态框展示当前用户的详细账号信息。
return (
<>
<Dropdown menu={{ selectedKeys, items: menuItems, onClick }}>
{children}
</Dropdown>
// 返回一个包含两个主要元素的 React 片段(<>...</>),第一个元素是 'Dropdown' 组件,用于创建一个下拉菜单,通过其'menu' 属性传入一个配置对象,包含:
//'selectedKeys' 状态变量,用于显示当前选中的菜单项(比如当前登录用户对应的菜单项处于选中状态);
// 'items' 属性传入上面构建好的'menuItems' 数组,定义了整个下拉菜单的结构和内容;
// 'onClick' 事件处理函数传入之前定义的 'onClick' 函数,用于处理各个菜单项被点击时的具体操作逻辑。
// 在 'Dropdown' 组件内部,渲染传入的 'children' 属性对应的内容,这样可以根据使用该组件的地方传入不同的子元素,使下拉菜单可以灵活地嵌入到不同的页面布局中,例如可以在一个按钮上添加下拉菜单功能等。
<Modal open={isModalOpen} onOk={handleUserInfoOk} onCancel={handleUserInfoCancel} width={1000}>
<Descriptions title="账号信息">

@ -1,29 +1,53 @@
import { Typography } from 'antd';
// 从 Ant Design'antd')库中导入 'Typography' 组件,这个组件主要用于处理文本相关的展示样式和排版等功能,在前端页面中方便统一管理和呈现各类文本内容。
import React from 'react';
// 导入 React 核心库,这是使用 React 框架编写组件的基础,所有的 React 组件和相关功能都依赖于此库来实现。
import { getNickname } from '@/services/User';
// 从项目中相对路径为 '@/services/User' 的模块里导入名为 'getNickname' 的函数,从函数名推测它的功能大概率是向服务器端发起请求,获取用户的昵称信息,为后续在组件中展示用户昵称做准备。
import { useState, useEffect } from 'react';
// 导入 React 框架提供的两个常用 Hook'useState' 和 'useEffect'。
// 'useState' 用于在函数组件里定义和管理状态,使得组件能够根据状态的变化重新渲染,呈现不同的界面内容;
// 'useEffect' 用于在函数组件中执行副作用操作,像发起网络请求、订阅数据更新、操作 DOM 等,在这里主要用于在组件挂载时获取用户昵称数据。
const { Text } = Typography;
// 通过解构赋值从 'Typography' 组件中获取 'Text' 组件,'Text' 组件通常用于在页面上展示普通文本内容,并且会应用 Ant Design 定义好的文本相关样式,使文本展示更加美观、规范,这里将用它来展示获取到的用户昵称。
const UserName: React.FC = () => {
// 定义一个名为 'UserName' 的函数式组件,遵循 React.FCFunction Component类型定义它是一个接收 props属性并返回 React 元素的函数,此组件的主要功能就是获取并展示用户昵称。
const [nickname, setNickname] = useState<string>();
// 使用 'useState' hook 创建一个名为 'nickname' 的状态变量,初始值设为 undefined因为类型定义为字符串类型这里默认就是 undefined
// 这个状态变量用于存储从服务器获取到的用户昵称信息,后续会根据实际获取的数据进行更新,一旦更新,组件会重新渲染,进而展示新的昵称内容。
const handleNickname = async () => {
// 定义一个名为 'handleNickname' 的异步函数,其主要作用是处理获取用户昵称的操作。
try {
const response = await getNickname();
// 调用之前导入的 'getNickname' 函数,它返回一个 Promise通过 'await' 等待这个 Promise 被成功 resolve即请求完成并返回数据
// 将返回的结果赋值给'response' 变量,这里的结果应该包含了获取用户昵称操作的相关信息,比如是否成功获取以及具体的昵称数据等。
if (response.success) {
// 判断服务器返回的结果中'success' 属性是否为 true也就是判断是否成功获取到了用户昵称如果成功获取到了。
setNickname(response.data);
// 则从'response' 变量中取出 'data' 属性(假设服务器返回的数据结构中有 'data' 字段存放实际的用户昵称内容),
// 再使用'setNickname' 函数更新 'nickname' 状态变量,这样组件会根据新的昵称数据重新渲染,进而在界面上展示出正确的用户昵称。
}
} catch (error) {
console.error(error);
// 如果在请求用户昵称的过程中出现错误,比如网络连接问题、服务器返回错误等,通过 'console.error' 把错误信息打印到控制台,便于进行调试和错误排查。
}
};
useEffect(() => {
handleNickname();
}, []);
// 使用 'useEffect' hook传入一个回调函数这里是调用 'handleNickname' 函数来获取用户昵称)和一个空的依赖项数组 []。
// 空的依赖项数组意味着这个副作用操作(获取用户昵称)只会在组件初次挂载时执行一次,即组件加载完成后会立即发起获取用户昵称的请求,获取到数据后用于后续展示。
return <Text>{nickname}</Text>;
// 返回一个 'Text' 组件,将 'nickname' 状态变量作为其内容展示出来,这样一旦 'nickname' 状态变量获取到了正确的用户昵称数据,就会通过 'Text' 组件展示在界面上,呈现给用户。
};
export default UserName;
// 将定义好的 'UserName' 函数式组件作为默认导出,方便其他模块在需要展示用户昵称的地方导入并使用这个组件,使其融入到更复杂的前端页面结构之中。

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save