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

13 KiB
Raw Permalink Blame History

系统配置与审计通知中心实施计划

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脚本

-- 字典类型表
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脚本

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

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: 提交

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:

@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>

示例:

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
@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: 测试