docs(project-summary): 新增项目总结文档及内容

- 添加了“项目总结”侧边栏项,支持目录折叠,方便访问汇总内容
- 新增Cursor进阶指南文档,详解Agent模式、Composer与快捷键等高级功能
- 编写权限管理系统文档,包含系统设计、权限架构及详细使用说明
- 新添服务总线学习文档,解析@BusService注解与CGLIB动态代理机制
- 录制回放权限配置说明,新增录像回放权限位及权限隔离策略
- 提供数据库配置脚本及实施步骤,确保权限配置准确高效
This commit is contained in:
liumangmang
2026-03-05 11:54:52 +08:00
parent eaab26940d
commit 83dc5bf7c6
6 changed files with 2368 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
---
title: 项目总结
index: false
icon: mdi:book-open-page-variant
category:
- 工作
---
<Catalog />

View File

@@ -0,0 +1,225 @@
---
icon: mdi:video-outline
date: 2026-03-05
category:
- 工作
- 项目总结
tag:
- 权限配置
- 录像回放
title: 录像回放权限配置说明
---
录像回放权限配置说明
<!-- more -->
# 录像回放权限配置说明
## 概述
根据系统权限说明文档中的权限隔离原则为录像回放相关功能设置了单独的权限位权限位21RECORD_PLAYBACK实现与实时监控权限的独立控制。
## 修改内容
### 1. 权限常量定义
**文件**: `platapp/04_sunri-web-patrol/sunri-web-center-utils/src/main/java/com/sunri/constant/RightConstant.java`
**修改内容**: 添加录像回放权限常量
```java
// 录像回放: 操作员,对应实时监控->录像回放相关界面的浏览、查询权限
public static final int RECORD_PLAYBACK = 21;
```
同时更新了操作员权限注释,增加 `RECORD_PLAYBACK` 权限位。
### 2. Controller API权限注解更新
#### 2.1 HighDefinitionVideoEquipmentController.java
**文件**: `platapp/04_sunri-web-patrol/sunri-web-center-cygbusiness/cygbusiness-model/src/main/java/com/sunri/model/controller/account/HighDefinitionVideoEquipmentController.java`
**修改的API方法**:
- `getVideoFileList` - 录像-获取文件列表
- `getVideoFileUrl` - 录像-获取回放地址
- `stopVideoFileUrl` - 录像-停止回放/推流
- `videoPlayBackControl` - 录像-回放控制
- `videoProgress` - 录像-进度获取
- `getAfterCalibrationStartTime` - 录像-获取校准后开始时间
**权限变更**: 从 `@ApiRight(value = {REAL_TIME_MONITORING})` 改为 `@ApiRight(value = {RECORD_PLAYBACK})`
#### 2.2 ResourceController.java
**文件**: `platapp/04_sunri-web-patrol/sunri-web-center-standalone/standalone-patrol/src/main/java/com/sunri/controller/ResourceController.java`
**修改的API方法**:
- `downloadVideoChunk` - 下载文件到浏览器(分片)
- `getDownloadChunkSize` - 获取下载文件分片数
**权限变更**: 从 `@ApiRight(value = {REAL_TIME_MONITORING, ALGORITHM_VERIFICATION})` 改为 `@ApiRight(value = {REAL_TIME_MONITORING, RECORD_PLAYBACK, ALGORITHM_VERIFICATION})`
#### 2.3 HighDefinitionVideoMonitorController.java
**文件**: `platapp/04_sunri-web-patrol/sunri-web-center-cygbusiness/cygbusiness-model/src/main/java/com/sunri/model/controller/monitor/HighDefinitionVideoMonitorController.java`
**修改的API方法**:
- `videoDownload` - 录像-开始下载/手动录像
**权限变更**: 从 `@ApiRight(value = {DEVICE_CONTROL})` 改为 `@ApiRight(value = {RECORD_PLAYBACK})`
### 3. 数据库配置脚本
```sql
-- 录像回放权限配置脚本
-- 功能为录像回放相关功能添加权限位21RECORD_PLAYBACK的单独控制
-- 1. 添加录像回放权限常量到 cfg_auth_const 表
INSERT INTO cfg_auth_const (right, description, create_time, update_time)
VALUES (21, '录像回放', NOW(), NOW())
ON DUPLICATE KEY UPDATE description = '录像回放', update_time = NOW();
-- 2. 查找录像回放相关的菜单ID
-- SELECT id, name, nodeid, url FROM cfg_menu WHERE name LIKE '%录像%' OR name LIKE '%回放%';
-- 3. 为录像回放菜单绑定权限位21按实际菜单修改
-- INSERT INTO cfg_resource_right (resource_id, right)
-- VALUES (7, 21)
-- ON DUPLICATE KEY UPDATE right = 21;
-- INSERT INTO cfg_resource_right (resource_id, right)
-- SELECT id, 21 FROM cfg_menu WHERE nodeid = 'LXHF'
-- ON DUPLICATE KEY UPDATE right = 21;
-- 4. 更新角色权限配置(示例)
-- UPDATE user_role_info SET role_authority = role_authority | 2097152 WHERE role_name = '操作员';
-- UPDATE user_role_info SET role_authority = role_authority | 2097216 WHERE role_name = '监控操作员';
-- UPDATE user_role_info SET role_authority = role_authority | 2097152 WHERE role_name = '录像查询员';
-- 5. 验证配置
-- SELECT * FROM cfg_auth_const WHERE right = 21;
-- SELECT mr.*, m.name, m.nodeid FROM cfg_resource_right mr JOIN cfg_menu m ON mr.resource_id = m.id WHERE mr.right = 21;
-- SELECT role_id, role_name, role_authority, (role_authority & 2097152) > 0 AS has_record_playback_permission FROM user_role_info;
-- 回滚SQL
-- DELETE FROM cfg_auth_const WHERE right = 21;
-- DELETE FROM cfg_resource_right WHERE right = 21;
-- UPDATE user_role_info SET role_authority = role_authority & ~2097152 WHERE role_authority & 2097152 > 0;
```
## 权限隔离优势
通过将录像回放权限从实时监控权限中独立出来,实现了以下优势:
| 场景 | 实时监控权限(6) | 录像回放权限(21) | 说明 |
|------|----------------|------------------|------|
| 实时监控员 | ✅ | ❌ | 只能查看实时监控画面 |
| 录像查询员 | ❌ | ✅ | 只能查看历史录像回放 |
| 监控操作员 | ✅ | ✅ | 既能看实时监控也能看录像回放 |
| 数据分析员 | ❌ | ✅ | 只能进行录像数据分析 |
## 实施步骤
### 代码修改(已完成)
1. ✅ 在 `RightConstant.java` 中添加 `RECORD_PLAYBACK = 21` 常量
2. ✅ 更新录像回放相关API的权限注解
3. ✅ 创建数据库配置脚本
### 数据库配置(需要手动执行)
1. 备份数据库
2. 执行上文中的 SQL 配置脚本
3. 根据实际菜单数据确认录像回放菜单的ID或nodeid
4. 更新角色权限配置
5. 验证配置是否正确
### 系统部署
1. 编译代码
2. 部署应用
3. 执行数据库配置脚本
4. 相关用户重新登录以获取新权限
## 权限位计算
- **权限位21的值**: 2^21 = 2,097,152
- **实时监控权限位6的值**: 2^6 = 64
- **同时拥有实时监控和录像回放权限**: 64 + 2,097,152 = 2,097,216
### 角色权限配置示例
```sql
-- 操作员:增加录像回放权限
UPDATE user_role_info SET role_authority = role_authority | 2097152 WHERE role_name = '操作员';
-- 监控操作员:拥有实时监控和录像回放权限
UPDATE user_role_info SET role_authority = role_authority | 2097216 WHERE role_name = '监控操作员';
-- 录像查询员:只拥有录像回放权限
UPDATE user_role_info SET role_authority = role_authority | 2097152 WHERE role_name = '录像查询员';
```
## 注意事项
1. **数据库备份**: 执行数据库脚本前,请务必备份数据库
2. **菜单确认**: 脚本中的菜单ID需要根据实际情况进行确认和修改
3. **角色权限**: 角色权限配置需要根据实际业务需求进行调整
4. **用户登录**: 修改角色权限后,相关用户需要重新登录才能生效
5. **权限测试**: 部署后请进行全面的权限测试,确保权限控制正确
## 回滚方案
如需回滚,请执行以下操作:
1. 恢复代码版本
2. 执行上文中的回滚 SQL 脚本
3. 重新部署应用
4. 相关用户重新登录
## 验证方法
### 代码验证
```bash
# 搜索所有使用RECORD_PLAYBACK权限的API
grep -r "RECORD_PLAYBACK" --include="*.java" platapp/
```
### 数据库验证
```sql
-- 查看权限常量
SELECT * FROM cfg_auth_const WHERE right = 21;
-- 查看菜单权限绑定
SELECT mr.*, m.name, m.nodeid
FROM cfg_resource_right mr
JOIN cfg_menu m ON mr.resource_id = m.id
WHERE mr.right = 21;
-- 查看角色权限
SELECT role_id, role_name, role_authority,
(role_authority & 2097152) > 0 AS has_record_playback_permission
FROM user_role_info;
```
### 功能验证
1. 创建只拥有录像回放权限的用户角色
2. 使用该角色登录系统
3. 验证只能访问录像回放功能,不能访问实时监控功能
4. 创建只拥有实时监控权限的用户角色
5. 使用该角色登录系统
6. 验证只能访问实时监控功能,不能访问录像回放功能
## 相关文档
- 权限管理系统文档.md: 完整的权限管理说明文档
## 版本信息
- **修改日期**: 2026-03-05
- **修改人员**: 系统管理员
- **版本**: 1.0.0
- **状态**: 已完成代码修改和数据库配置

View File

@@ -0,0 +1,202 @@
---
icon: mdi:transit-connection-variant
date: 2026-03-05
category:
- 工作
- 项目总结
tag:
- 服务总线
- CGLIB
- 权限系统
title: 服务总线学习
---
服务总线学习
<!-- more -->
# @BusService 注解与 CGLIB 动态代理机制学习记录
## 1. 概述
本次学习深入探讨了 `@BusService` 注解配合 CGLIB 动态代理实现的无本地实现接口代理机制,了解了服务总线架构中客户端如何通过动态代理调用远程服务。
## 2. @BusService 注解的作用
### 2.1 注解定义
`@BusService` 注解位于 `/platform/00_depends/00_sunri-bus-service-dependency-thrift/src/main/java/com/sunri/annotation/BusService.java`,包含以下关键属性:
- `name()` - 服务名称(如 "cygdevopsweb"
- `dataclass()` - 数据类别(如 "statistic"
- `app()` - 应用名称
- `datatype()` - 数据类型
### 2.2 注解处理流程
1. **扫描**`ServiceBusBeanAutoDefinitionConfig.definitionConsumer()` 方法扫描带有 `@BusService` 注解的接口
2. **验证**:检查注解有效性、服务名称、排除列表等
3. **过滤**:确保接口属于指定包名且未重复注册
## 3. CGLIB 动态代理机制
### 3.1 代理对象创建位置
`ServiceBusBeanAutoDefinitionConfig.java` 第409-445行的循环中
```java
if (c.isInterface()) { // 409行
if (!c.getName().contains(pkgname)) { // 410-412行
continue;
}
// ... 验证逻辑 ...
// Bean构建
BusService service = (BusService) c.getAnnotation(BusService.class); // 417行
if (service == null || "".equals(service.name()) || exclude.contains(service.name())) {
continue;
}
// 创建服务信息
ServiceInfo serviceInfo = new ServiceInfo(); // 425行
serviceInfo.setPaname(StringUtils.isEmpty(service.app()) ? busClientConfig.getPaname() : service.app());
serviceInfo.setServname(service.name());
// ... 设置其他服务信息
// 注册Bean定义
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(c); // 434行
GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();
definition.getPropertyValues().add("interfaceClass", c); // 436行
definition.getPropertyValues().add("serviceInfo", serviceInfo); // 437行
definition.getPropertyValues().add("clientManager", clientManager); // 438行
definition.setBeanClass(BusClientFactoryBean.class); // 439行
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
String name = toLowerCaseFirstOne(c.getSimpleName()); // 442行
dbf.registerBeanDefinition(name, definition); // 443行
}
```
### 3.2 BusClientFactoryBean 核心实现
位于 `/platform/00_depends/00_sunri-bus-service-dependency-thrift/src/main/java/com/sunri/client/mapper/BusClientFactoryBean.java`
```java
@Override
public T getObject() throws Exception {
enhancer.setSuperclass(interfaceClass); // 29行 设置要代理的接口
interceptor.setClientManager(clientManager); // 30行 设置客户端管理器
interceptor.setServiceInfo(serviceInfo); // 31行 设置服务信息
enhancer.setCallback(interceptor); // 32行 设置拦截器
return (T) enhancer.create(); // 33行 创建代理对象
}
```
### 3.3 BusClientInterceptor 拦截器
位于 `/platform/00_depends/00_sunri-bus-service-dependency-thrift/src/main/java/com/sunri/client/mapper/BusClientInterceptor.java`
- 拦截所有接口方法调用
- 将本地方法调用转换为远程服务调用
- 通过 Thrift 协议发送到远程服务端
## 4. Spring Bean 生命周期集成
### 4.1 Bean 定义注册
- **触发位置**`ServiceBusBeanAutoDefinitionConfig.postProcessBeanDefinitionRegistry()`
- **执行时机**Spring 容器启动时,在 `BeanDefinitionRegistryPostProcessor` 阶段
- **结果**:将每个带 `@BusService` 注解的接口注册为由 `BusClientFactoryBean` 创建的 Bean
### 4.2 属性自动注入机制
`ServiceBusBeanAutoDefinitionConfig.definitionConsumer()` 第436-438行
```java
definition.getPropertyValues().add("interfaceClass", c); // 接口类
definition.getPropertyValues().add("serviceInfo", serviceInfo); // 服务信息
definition.getPropertyValues().add("clientManager", clientManager); // 客户端管理器
```
Spring 框架内部通过反射机制自动调用对应的 setter 方法:
- `setInterfaceClass()` → 注入接口类
- `setServiceInfo()` → 注入服务信息
- `setClientManager()` → 注入客户端管理器
### 4.3 Bean 实例化
当应用通过 `@Autowired``context.getBean()` 获取接口实例时:
1. Spring 发现该 Bean 由 `BusClientFactoryBean` 创建
2. 调用 `BusClientFactoryBean.getObject()`
3. CGLIB 创建动态代理对象
4. 返回代理对象给应用
## 5. 工作流程总结
```
应用启动 → ServiceBusBeanAutoDefinitionConfig 扫描 @BusService 注解的接口
为每个接口创建 BusClientFactoryBean 定义并注册到 Spring 容器
应用代码获取接口实例 (@Autowired 或 getBean)
Spring 调用 BusClientFactoryBean.getObject()
CGLIB 创建接口的动态代理对象
应用调用接口方法时由 BusClientInterceptor 拦截
拦截器将方法调用转换为远程服务调用
通过 Thrift 协议发送到远程服务端执行
返回结果给调用方
```
## 6. 关键特点
### 6.1 透明性
- 客户端代码无需关心底层网络通信
- 接口调用如同本地调用一样简单
### 6.2 解耦性
- 客户端只依赖接口定义
- 无需知道服务实现的位置和细节
### 6.3 动态性
- 运行时动态生成代理类
- 支持灵活的服务定位和负载均衡
## 7. Spring FactoryBean属性注入机制
### 7.1 RegisterCenterClientFactoryBean属性注入流程
**调用位置**`ServiceBusBeanAutoDefinitionConfig.postProcessBeanDefinitionRegistry()` 第211-218行
**实现机制**
1. **属性值设置**:通过`BeanDefinition.getPropertyValues().add()`方法设置属性
2. **自动注入**Spring容器在Bean创建过程中自动调用对应的setter方法
3. **多态引用**`private RegisterCenterClient client`字段声明为接口类型,运行时指向`RegisterCenterDefaultClient`实例
**上下文依赖**
- 依赖Spring的Bean生命周期管理
-需要BeanDefinitionRegistryPostProcessor阶段的支持
- 依赖属性编辑器和类型转换机制
### 7.2完整调用链
```java
// 1. 创建Bean定义
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(RegisterCenterClient.class);
GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();
// 2. 设置属性值(关键步骤)
definition.getPropertyValues().add("interfaceClass", RegisterCenterClient.class);
definition.getPropertyValues().add("client", zkClient); // zkClient是RegisterCenterDefaultClient实例
// 3.指定FactoryBean类
definition.setBeanClass(RegisterCenterClientFactoryBean.class);
// 4. Spring内部调用setter方法
// setInterfaceClass(RegisterCenterClient.class)
// setClient(RegisterCenterDefaultClient实例)
// 5. getObject()返回具体实现
@Override
public T getObject() throws Exception {
return (T) client; // 返回RegisterCenterDefaultClient实例
}
```
## 8.技术栈
- **CGLIB**:用于动态代理类生成
- **Spring Framework**:用于 Bean 生命周期管理和依赖注入
- **Thrift**:用于远程服务通信协议
- **Zookeeper**:用于服务注册与发现
- **Curator**用于Zookeeper客户端连接管理

File diff suppressed because it is too large Load Diff