Files
novalon-manage-system/docs/plans/2026-03-11-system-config-audit-notice-plan.md
T

436 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 系统配置与审计通知中心实施计划
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** 完成系统配置(字典管理、系统参数)、审计中心(登录日志、操作日志、异常追踪)、通知中心(系统公告、消息推送WebSocket)、文件管理(上传/下载/预览)的数据库持久化与功能完善
**Architecture:** 基于Spring R2DBC响应式架构,遵循现有分层模式(Handler->Service->Repository->Entity),使用H2/PostgreSQL + Caffeine缓存,消息推送采用WebSocket
**Tech Stack:** Spring WebFlux, Spring Data R2DBC, H2/PostgreSQL, Caffeine, WebSocket, Lombok
---
## 第一阶段:数据层基础设施建设
### Task 1: 创建数据库表SQL脚本
**Files:**
- Modify: `docs/sql/init.sql` (创建以下表)
**Step 1: 编写SQL脚本**
```sql
-- 字典类型表
CREATE TABLE IF NOT EXISTS sys_dict_type (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
dict_name VARCHAR(100) NOT NULL COMMENT '字典名称',
dict_type VARCHAR(100) NOT NULL UNIQUE COMMENT '字典类型',
status VARCHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
remark VARCHAR(500) COMMENT '备注',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted_at TIMESTAMP
);
-- 字典数据表
CREATE TABLE IF NOT EXISTS sys_dict_data (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
dict_sort INT DEFAULT 0 COMMENT '字典排序',
dict_label VARCHAR(100) NOT NULL COMMENT '字典标签',
dict_value VARCHAR(100) NOT NULL COMMENT '字典键值',
dict_type VARCHAR(100) NOT NULL COMMENT '字典类型',
css_class VARCHAR(100) COMMENT '样式属性',
list_class VARCHAR(100) COMMENT '表格回显样式',
is_default VARCHAR(1) DEFAULT 'N' COMMENT '是否默认(Y是 N否)',
status VARCHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted_at TIMESTAMP
);
-- 系统配置表
CREATE TABLE IF NOT EXISTS sys_config (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
config_name VARCHAR(100) NOT NULL COMMENT '配置名称',
config_key VARCHAR(100) NOT NULL UNIQUE COMMENT '配置键名',
config_value VARCHAR(500) NOT NULL COMMENT '配置值',
config_type VARCHAR(1) DEFAULT 'N' COMMENT '系统内置(Y是 N否)',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted_at TIMESTAMP
);
-- 登录日志表
CREATE TABLE IF NOT EXISTS sys_login_log (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) COMMENT '用户名',
ip VARCHAR(50) COMMENT 'IP地址',
location VARCHAR(255) COMMENT '登录位置',
browser VARCHAR(50) COMMENT '浏览器类型',
os VARCHAR(50) COMMENT '操作系统',
status VARCHAR(1) COMMENT '登录状态(0成功 1失败)',
message VARCHAR(255) COMMENT '提示消息',
login_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 异常日志表
CREATE TABLE IF NOT EXISTS sys_exception_log (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) COMMENT '用户名',
title VARCHAR(100) COMMENT '异常标题',
exception_name VARCHAR(100) COMMENT '异常名称',
method_name VARCHAR(100) COMMENT '方法名称',
method_params TEXT COMMENT '方法参数',
exception_msg TEXT COMMENT '异常信息',
exception_stack TEXT COMMENT '堆栈信息',
ip VARCHAR(50) COMMENT 'IP地址',
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 系统公告表
CREATE TABLE IF NOT EXISTS sys_notice (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
notice_title VARCHAR(100) NOT NULL COMMENT '公告标题',
notice_type VARCHAR(1) DEFAULT '1' COMMENT '公告类型(1通知 2公告)',
notice_content TEXT COMMENT '公告内容',
status VARCHAR(1) DEFAULT '0' COMMENT '公告状态(0正常 1关闭)',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted_at TIMESTAMP
);
-- 文件管理表
CREATE TABLE IF NOT EXISTS sys_file (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
file_name VARCHAR(255) NOT NULL COMMENT '文件名',
file_path VARCHAR(500) NOT NULL COMMENT '文件路径',
file_size VARCHAR(50) COMMENT '文件大小',
file_type VARCHAR(50) COMMENT '文件类型',
storage_type VARCHAR(20) DEFAULT 'local' COMMENT '存储类型(local/oss/s3',
create_by VARCHAR(50) COMMENT '创建者',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP
);
-- 用户消息表(消息推送用)
CREATE TABLE IF NOT EXISTS sys_user_message (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL COMMENT '接收用户ID',
title VARCHAR(100) COMMENT '消息标题',
content TEXT COMMENT '消息内容',
message_type VARCHAR(1) DEFAULT '1' COMMENT '消息类型(1系统 2通知)',
is_read VARCHAR(1) DEFAULT '0' COMMENT '是否已读(0未读 1已读)',
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
**Step 2: 提交SQL脚本**
```bash
git add docs/sql/init.sql
git commit -m "feat: 添加系统配置和审计模块数据库表脚本"
```
---
### Task 2: 创建字典类型Entity
**Files:**
- Create: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/infrastructure/db/entity/SysDictTypeEntity.java`
- Modify: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/infrastructure/db/entity/BaseEntity.java`
**Step 1: 在BaseEntity添加公共字段**
查看现有BaseEntity确保包含:
- id, createdAt, updatedAt, deletedAt
**Step 2: 创建SysDictTypeEntity**
```java
package cn.novalon.manage.sys.infrastructure.db.entity;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;
@Table("sys_dict_type")
public class SysDictTypeEntity {
@Id
private Long id;
@Column("dict_name")
private String dictName;
@Column("dict_type")
private String dictType;
@Column("status")
private String status;
@Column("remark")
private String remark;
@Column("created_at")
private LocalDateTime createdAt;
@Column("updated_at")
private LocalDateTime updatedAt;
@Column("deleted_at")
private LocalDateTime deletedAt;
// Getters and Setters
}
```
**Step 3: 提交**
```bash
git add entity/SysDictTypeEntity.java
git commit -m "feat: 添加字典类型Entity"
```
---
### Task 3: 创建其他Entity(字典数据、系统配置、登录日志、异常日志、公告、文件、消息)
**Files:**
- Create: `infrastructure/db/entity/SysDictDataEntity.java`
- Create: `infrastructure/db/entity/SysConfigEntity.java`
- Create: `infrastructure/db/entity/SysLoginLogEntity.java`
- Create: `infrastructure/db/entity/SysExceptionLogEntity.java`
- Create: `infrastructure/db/entity/SysNoticeEntity.java`
- Create: `infrastructure/db/entity/SysFileEntity.java`
- Create: `infrastructure/db/entity/SysUserMessageEntity.java`
**每Entity结构:** 继承BaseEntity,添加对应字段的@Column注解和getter/setter
**示例 - SysConfigEntity:**
```java
@Table("sys_config")
public class SysConfigEntity {
@Id
private Long id;
@Column("config_name")
private String configName;
@Column("config_key")
private String configKey;
@Column("config_value")
private String configValue;
@Column("config_type")
private String configType;
@Column("created_at")
private LocalDateTime createdAt;
@Column("updated_at")
private LocalDateTime updatedAt;
@Column("deleted_at")
private LocalDateTime deletedAt;
// Getters and Setters
}
```
---
### Task 4: 创建Repository接口
**Files:**
- Create: `infrastructure/db/repository/SysDictTypeRepository.java`
- Create: `infrastructure/db/repository/SysDictDataRepository.java`
- Create: `infrastructure/db/repository/SysConfigRepository.java`
- Create: `infrastructure/db/repository/SysLoginLogRepository.java`
- Create: `infrastructure/db/repository/SysExceptionLogRepository.java`
- Create: `infrastructure/db/repository/SysNoticeRepository.java`
- Create: `infrastructure/db/repository/SysFileRepository.java`
- Create: `infrastructure/db/repository/SysUserMessageRepository.java`
**每Repository:** 继承 ReactiveCrudRepository<Entity, Long>
**示例:**
```java
package cn.novalon.manage.sys.infrastructure.db.repository;
import cn.novalon.manage.sys.infrastructure.db.entity.SysDictTypeEntity;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface SysDictTypeRepository extends ReactiveCrudRepository<SysDictTypeEntity, Long> {
}
```
---
## 第二阶段:领域层(Domain + Converter
### Task 5: 更新Domain模型
**Files:**
- Modify: `core/domain/SysDictType.java` - 添加dictDataList字段
- Modify: `core/domain/SysDictData.java` - 确保字段完整
- Modify: `core/domain/SysConfig.java` - 确保字段完整
- Modify: `core/domain/SysLoginLog.java` - 确保字段完整
- Create: `core/domain/SysExceptionLog.java`
- Create: `core/domain/SysUserMessage.java`
---
### Task 6: 创建Converter转换器
**Files:**
- Create: `infrastructure/db/converter/SysDictTypeConverter.java`
- Create: `infrastructure/db/converter/SysDictDataConverter.java`
- Create: `infrastructure/db/converter/SysConfigConverter.java`
- Create: `infrastructure/db/converter/SysLoginLogConverter.java`
- Create: `infrastructure/db/converter/SysExceptionLogConverter.java`
- Create: `infrastructure/db/converter/SysNoticeConverter.java`
- Create: `infrastructure/db/converter/SysFileConverter.java`
---
## 第三阶段:服务层(Service)
### Task 7: 创建Service接口和实现
**Files:**
- Create: `core/service/ISysDictTypeService.java` + `impl/SysDictTypeServiceImpl.java`
- Create: `core/service/ISysDictDataService.java` + `impl/SysDictDataServiceImpl.java`
- Create: `core/service/ISysConfigService.java` + `impl/SysConfigServiceImpl.java`
- Create: `core/service/ISysLoginLogService.java` + `impl/SysLoginLogServiceImpl.java`
- Create: `core/service/ISysExceptionLogService.java` + `impl/SysExceptionLogServiceImpl.java`
- Create: `core/service/ISysNoticeService.java` + `impl/SysNoticeServiceImpl.java`
- Create: `core/service/ISysFileService.java` + `impl/SysFileServiceImpl.java`
- Create: `core/service/ISysUserMessageService.java` + `impl/SysUserMessageServiceImpl.java`
**核心方法:**
- CRUD操作
- 字典: 根据类型查询数据列表
- 配置: 根据key查询value
- 日志: 分页查询、按条件筛选
- 消息: 查询用户未读消息
---
## 第四阶段:Handler层(API接口)
### Task 8: 重构Handler接入数据库
**Files:**
- Modify: `handler/sys/SysDictHandler.java` - 注入Service替换内存Map
- Modify: `handler/sys/SysConfigHandler.java` - 注入Service替换内存Map
- Modify: `handler/sys/SysLogHandler.java` - 添加登录日志和异常日志查询
- Modify: `handler/sys/SysNoticeHandler.java` - 注入Service替换内存Map
- Modify: `handler/sys/SysFileHandler.java` - 完善文件预览功能
---
## 第五阶段:消息推送(WebSocket)
### Task 9: WebSocket配置
**Files:**
- Create: `config/WebSocketConfig.java`
- Create: `handler/websocket/WebSocketHandler.java`
- Create: `service/impl/WebSocketService.java`
```java
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(webSocketHandler(), "/ws")
.setAllowedOrigins("*");
}
@Bean
public WebSocketHandler webSocketHandler() {
return new WebSocketHandler();
}
}
```
---
### Task 10: 消息推送Service
**Files:**
- Create: `core/service/IWebSocketService.java`
- Create: `core/service/impl/WebSocketServiceImpl.java`
**功能:**
- 发送消息给指定用户
- 发送消息给所有在线用户
- 用户上线/下线跟踪
---
## 第六阶段:完善文件预览
### Task 11: 文件预览支持
**Files:**
- Modify: `handler/sys/SysFileHandler.java` - 添加预览接口
- 创建DTO: `dto/response/FilePreviewResponse.java`
**预览支持:**
- 图片: 返回Base64或直接流
- PDF: 返回PDF流
- 文本: 返回文本内容
---
## 第七阶段:异常日志自动记录
### Task 12: 全局异常处理器
**Files:**
- Create: `handler/GlobalExceptionHandler.java`
- Create: `config/GlobalExceptionHandlerConfig.java`
**功能:**
- 捕获所有Controller异常
- 自动记录到sys_exception_log表
- 返回统一格式的错误响应
---
## 第八阶段:测试
### Task 13: 单元测试
**Files:**
- Create: `test/service/SysDictTypeServiceTest.java`
- Create: `test/service/SysConfigServiceTest.java`
- Create: `test/service/SysLoginLogServiceTest.java`
- Create: `test/handler/SysDictHandlerTest.java`
- Create: `test/handler/SysNoticeHandlerTest.java`
**测试覆盖:**
- Service层CRUD操作
- Handler层API响应
- 异常场景处理
---
## 实施顺序
1. Task 1: SQL脚本
2. Task 2-4: Entity + Repository
3. Task 5-6: Domain + Converter
4. Task 7: Service层
5. Task 8: Handler层重构
6. Task 9-10: WebSocket消息推送
7. Task 11: 文件预览
8. Task 12: 异常日志
9. Task 13: 测试