From 8dd0efa09e4784721dc19307bcf00439c8962ef0 Mon Sep 17 00:00:00 2001 From: chaos Date: Thu, 20 Nov 2025 23:01:30 +0800 Subject: [PATCH] =?UTF-8?q?feat(database):=20=E9=87=8D=E6=9E=84=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E8=A7=92=E8=89=B2=E5=85=B3=E8=81=94=E5=8F=8A=E6=9D=83?= =?UTF-8?q?=E9=99=90=E4=BD=93=E7=B3=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 BizException 构造函数支持自定义消息 - 优化 SQL 脚本结构,明确表设计最佳实践 - 修改 t_user、t_role 等表字段类型与索引策略 - 引入代理主键 id 到关联表 t_user_role 和 t_role_permission - 更新 UserRole 实体类适配 MyBatis-Plus 主键策略 - 增强 UserRoleService 接口功能,支持分配和撤销角色 - 实现批量操作和事务控制提升数据一致性 - 添加安全注解 @PreAuthorize 控制接口访问权限 - 修正 Mapper 注解并优化参数命名提高可读性 - 扩展 ErrorCode 常量增强错误描述准确性 --- .../chaos_api/common/constants/ErrorCode.java | 9 +- .../common/exceotion/BizException.java | 4 + .../cn/nopj/chaos_api/mapper/UserMapper.java | 13 +- .../nopj/chaos_api/mapper/UserRoleMapper.java | 11 + .../chaos_api/domain/entity/UserRole.java | 9 +- .../chaos_api/service/UserRoleService.java | 14 +- .../service/impl/UserRoleServiceImpl.java | 97 ++++++-- .../chaos_api/controller/RoleController.java | 14 +- chaos_api_web/src/main/resources/data.sql | 234 ++++++++++-------- 9 files changed, 273 insertions(+), 132 deletions(-) diff --git a/chaos_api_common/src/main/java/cn/nopj/chaos_api/common/constants/ErrorCode.java b/chaos_api_common/src/main/java/cn/nopj/chaos_api/common/constants/ErrorCode.java index 3015be3..78b7a0b 100644 --- a/chaos_api_common/src/main/java/cn/nopj/chaos_api/common/constants/ErrorCode.java +++ b/chaos_api_common/src/main/java/cn/nopj/chaos_api/common/constants/ErrorCode.java @@ -30,9 +30,12 @@ public enum ErrorCode { PHONE_EXISTS(409, "USER-109", "手机号已注册"), PHONE_FORMAT_ERROR(400, "USER-110", "手机号格式无效"), USER_UPDATE_USERNAME_FAILED(400,"USER-111" , "用户名更新失败"), + // 用户组 + ROLE_REVOKE_FAILED(400,"USER-112" ,"用户组删除失败" ), - - ROLE_ID_INVALID(400, "ROLE-100" , "角色ID无效" ), + ROLE_ID_EXISTS(400, "ROLE-100" , "角色ID已存在" ), + ROLE_ID_INVALID(400, "ROLE-101" , "角色ID无效" ), + ROLE_ID_NOT_EXISTS(400, "ROLE-102" , "角色ID不存在"), // ================== 论坛内容相关 (200-299) ================== POST_NOT_FOUND(404, "POST-201", "帖子不存在"), @@ -47,7 +50,7 @@ public enum ErrorCode { CAPTCHA_ERROR(400, "SYS-301", "验证码错误"), SMS_SEND_FAILED(500, "SYS-302", "短信发送失败"), FILE_UPLOAD_FAILED(500, "SYS-303", "文件上传失败"), - RATE_LIMIT_EXCEEDED(429, "SYS-304", "操作过于频繁"),; + RATE_LIMIT_EXCEEDED(429, "SYS-304", "操作过于频繁"); private final int httpStatus; private final String code; // 业务错误码(领域-编号) diff --git a/chaos_api_common/src/main/java/cn/nopj/chaos_api/common/exceotion/BizException.java b/chaos_api_common/src/main/java/cn/nopj/chaos_api/common/exceotion/BizException.java index 3528d24..5b10331 100644 --- a/chaos_api_common/src/main/java/cn/nopj/chaos_api/common/exceotion/BizException.java +++ b/chaos_api_common/src/main/java/cn/nopj/chaos_api/common/exceotion/BizException.java @@ -11,4 +11,8 @@ public class BizException extends RuntimeException{ super(errorCode.getMessage()); this.errorCode = errorCode; } + public BizException(String message) { + super(message); + this.errorCode = ErrorCode.SYSTEM_ERROR; + } } diff --git a/chaos_api_data/src/main/java/cn/nopj/chaos_api/mapper/UserMapper.java b/chaos_api_data/src/main/java/cn/nopj/chaos_api/mapper/UserMapper.java index 4f1a7d6..9bec986 100644 --- a/chaos_api_data/src/main/java/cn/nopj/chaos_api/mapper/UserMapper.java +++ b/chaos_api_data/src/main/java/cn/nopj/chaos_api/mapper/UserMapper.java @@ -32,12 +32,13 @@ public interface UserMapper extends BaseMapper { /** * 插入用户角色关系 - * @param id 用户id - * @param i 角色id + * 注意:已将注解由 @Select 修正为 @Insert,并优化了参数命名。 + * 由于 t_user_role 现在有自增主键 id,只需插入 user_id 和 role_id。 + * @param userId 用户id + * @param roleId 角色id */ - - @Select("INSERT INTO t_user_role (user_id, role_id) VALUES (#{userId}, #{roleId})") - void insertUserRole(@Param("userId") Long id, @Param("roleId") Long i); + @Insert("INSERT INTO t_user_role (user_id, role_id) VALUES (#{userId}, #{roleId})") + void insertUserRole(@Param("userId") Long userId, @Param("roleId") Long roleId); /** * 根据用户名查询用户信息 @@ -97,4 +98,4 @@ public interface UserMapper extends BaseMapper { many = @Many(select = "findRolesByUserId")) }) User findUserWithRolesByUsername(String username); -} +} \ No newline at end of file diff --git a/chaos_api_data/src/main/java/cn/nopj/chaos_api/mapper/UserRoleMapper.java b/chaos_api_data/src/main/java/cn/nopj/chaos_api/mapper/UserRoleMapper.java index a214160..d7a0962 100644 --- a/chaos_api_data/src/main/java/cn/nopj/chaos_api/mapper/UserRoleMapper.java +++ b/chaos_api_data/src/main/java/cn/nopj/chaos_api/mapper/UserRoleMapper.java @@ -2,6 +2,17 @@ package cn.nopj.chaos_api.mapper; import cn.nopj.chaos_api.domain.entity.UserRole; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Delete; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +@Mapper public interface UserRoleMapper extends BaseMapper { + /** + * 删除用户角色关系 + * @param userId 用户id + * @param roleId 角色id + */ + @Delete("DELETE FROM t_user_role WHERE user_id = #{userId} AND role_id = #{roleId}") + int delete(@Param("userId") Long userId,@Param("roleId") Long roleId); } diff --git a/chaos_api_domain/src/main/java/cn/nopj/chaos_api/domain/entity/UserRole.java b/chaos_api_domain/src/main/java/cn/nopj/chaos_api/domain/entity/UserRole.java index aa149b5..bc5eef3 100644 --- a/chaos_api_domain/src/main/java/cn/nopj/chaos_api/domain/entity/UserRole.java +++ b/chaos_api_domain/src/main/java/cn/nopj/chaos_api/domain/entity/UserRole.java @@ -1,13 +1,18 @@ package cn.nopj.chaos_api.domain.entity; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.AllArgsConstructor; +import lombok.Data; import lombok.NoArgsConstructor; @TableName("t_user_role") -@AllArgsConstructor -@NoArgsConstructor +@Data public class UserRole { + @TableId(value = "id", type = IdType.AUTO) + private Long id; // 虚拟字段,数据库可不存 + private Long userId; private Long roleId; } diff --git a/chaos_api_interface/src/main/java/cn/nopj/chaos_api/service/UserRoleService.java b/chaos_api_interface/src/main/java/cn/nopj/chaos_api/service/UserRoleService.java index 4bfe77b..95ce3c3 100644 --- a/chaos_api_interface/src/main/java/cn/nopj/chaos_api/service/UserRoleService.java +++ b/chaos_api_interface/src/main/java/cn/nopj/chaos_api/service/UserRoleService.java @@ -8,16 +8,16 @@ import java.util.List; * 用户角色服务 */ public interface UserRoleService { - /** - * 为用户设置角色 - * @param userId 用户id - * @param roles_id 角色id组 - */ - void setUserRole(Long userId, List roles_id); /** * 为用户设置角色 * @param request 请求参数 */ - void setUserRole(SetUserRoleRequest request); + void assignRolesToUser(SetUserRoleRequest request); + + /** + * 取消用户角色 + * @param request 角色id组 + */ + int revokeRolesFromUser(SetUserRoleRequest request); } diff --git a/chaos_api_service/src/main/java/cn/nopj/chaos_api/service/impl/UserRoleServiceImpl.java b/chaos_api_service/src/main/java/cn/nopj/chaos_api/service/impl/UserRoleServiceImpl.java index 886905e..48bee54 100644 --- a/chaos_api_service/src/main/java/cn/nopj/chaos_api/service/impl/UserRoleServiceImpl.java +++ b/chaos_api_service/src/main/java/cn/nopj/chaos_api/service/impl/UserRoleServiceImpl.java @@ -6,37 +6,87 @@ import cn.nopj.chaos_api.domain.entity.UserRole; import cn.nopj.chaos_api.dto.request.SetUserRoleRequest; import cn.nopj.chaos_api.mapper.UserRoleMapper; import cn.nopj.chaos_api.service.UserRoleService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; +import java.util.stream.Collectors; @Slf4j @Service -public class UserRoleServiceImpl implements UserRoleService { - - @Autowired - private UserRoleMapper userRoleMapper; +// 继承 ServiceImpl 以获得批量操作能力 +public class UserRoleServiceImpl extends ServiceImpl implements UserRoleService { + /** + * 批量分配角色给用户。 + */ + @Transactional(rollbackFor = Exception.class) @Override + public void assignRolesToUser(SetUserRoleRequest request) { + if (request == null || request.getUserId() == null || request.getUserId() <= 0L){ + throw new BizException(ErrorCode.USER_ID_INVALID); + } + Long userId = request.getUserId(); - public void setUserRole(Long userId, List roles_id) { + if (request.getRolesId() == null || request.getRolesId().isEmpty()){ + this.baseMapper.delete(new LambdaQueryWrapper().eq(UserRole::getUserId,userId)); + return; + } - for (Long role_id : roles_id) { - if (role_id == null || role_id == 0L) { - throw new BizException(ErrorCode.ROLE_ID_INVALID); - }else { - userRoleMapper.insert(new UserRole(userId, role_id)); + List rolesId = request.getRolesId(); + + // 1. 数据预校验:确保没有无效角色ID (0或null) + if (rolesId.stream().anyMatch(roleId -> roleId == null || roleId <= 0L)) { + throw new BizException(ErrorCode.ROLE_ID_INVALID); + } + + // 2. 构建批量插入列表 + List userRoleList = rolesId.stream() + .map(roleId -> { + var userRole = new UserRole(); + userRole.setUserId(userId); + userRole.setRoleId(roleId); + return userRole; + }) + .collect(Collectors.toList()); + + try { + + // 替代:先删除用户所有旧角色,再插入新的角色集合 (常用授权模式) + this.remove(new LambdaQueryWrapper().eq(UserRole::getUserId, userId)); + + // 保持原有逻辑:只添加新的角色 + boolean success = this.saveBatch(userRoleList); + + if (!success) { + // saveBatch 返回 false,通常是 MyBatis-Plus 内部错误或部分失败 + throw new BizException("批量分配角色操作失败。"); } + } catch (DataIntegrityViolationException e) { + // 捕获数据完整性约束失败 (如外键约束失败: role_id 不存在) + log.error("分配角色时外键约束失败: userId={}, rolesId={}", userId, rolesId, e); + + // 给出更具体的提示,可能需要检查是哪个 role_id 不存在 + throw new BizException("分配角色失败:列表中包含一个或多个不存在的角色ID。"); + } } + + /** + * 批量解除用户的角色关联。 + * 优化点: 使用 MyBatis-Plus 的批量删除,而不是在循环中单次删除。 + * @param request 包含用户ID和角色ID列表 + * @return 实际解除关联的记录数 + */ @Transactional(rollbackFor = Exception.class) @Override - public void setUserRole(SetUserRoleRequest request) { - if (request == null || request.getUserId() == null ){ + public int revokeRolesFromUser(SetUserRoleRequest request) { + if (request == null || request.getUserId() == null || request.getUserId() <= 0L){ throw new BizException(ErrorCode.USER_ID_INVALID); } if (request.getRolesId() == null || request.getRolesId().isEmpty()){ @@ -44,7 +94,22 @@ public class UserRoleServiceImpl implements UserRoleService { } Long userId = request.getUserId(); - List roles_id = request.getRolesId(); - setUserRole(userId, roles_id); + List rolesId = request.getRolesId(); + + + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(UserRole::getUserId, userId) + .in(UserRole::getRoleId, rolesId); // 批量删除指定的角色ID + + + int count = this.baseMapper.delete(wrapper); + + if (count == 0 && !rolesId.isEmpty()){ + // 如果用户传入了角色ID列表但删除了 0 行,可能是这些角色未分配给该用户 + log.warn("用户 {} 解除角色 {} 失败,0条记录被删除。", userId, rolesId); + throw new BizException("解除角色失败,用户可能未分配这些角色。"); + } + + return count; } -} +} \ No newline at end of file diff --git a/chaos_api_web/src/main/java/cn/nopj/chaos_api/controller/RoleController.java b/chaos_api_web/src/main/java/cn/nopj/chaos_api/controller/RoleController.java index 04a8e06..0e47364 100644 --- a/chaos_api_web/src/main/java/cn/nopj/chaos_api/controller/RoleController.java +++ b/chaos_api_web/src/main/java/cn/nopj/chaos_api/controller/RoleController.java @@ -6,6 +6,7 @@ import cn.nopj.chaos_api.model.ApiResult; import cn.nopj.chaos_api.service.UserRoleService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -28,9 +29,20 @@ public class RoleController { * @param request 请求参数 * @return 处理结果 */ + @PreAuthorize("hasAuthority('admin')") @RequestMapping("/setUserRole") public ApiResult setUserRole(@RequestBody SetUserRoleRequest request) { - userRoleService.setUserRole(request); + userRoleService.assignRolesToUser(request); return ApiResult.success("用户角色设置成功"); } + /** + * 取消用户角色 + * @param request 请求参数 + * @return 处理结果 + */ + @PreAuthorize("hasAuthority('admin')") + @RequestMapping("/cancelUserRole") + public ApiResult cancelUserRole(@RequestBody SetUserRoleRequest request) { + return ApiResult.success("用户角色取消成功",userRoleService.revokeRolesFromUser(request)); + } } diff --git a/chaos_api_web/src/main/resources/data.sql b/chaos_api_web/src/main/resources/data.sql index 986f398..2a1645a 100644 --- a/chaos_api_web/src/main/resources/data.sql +++ b/chaos_api_web/src/main/resources/data.sql @@ -1,132 +1,172 @@ +/** + * 数据库名称: chaos + * 编码和排序规则: UTF8MB4 / utf8mb4_general_ci (支持中文和Emoji) + * 存储引擎: InnoDB (支持事务和外键) + * 最佳实践调整: + * 1. 自动管理 create_time 和 update_time + * 2. 状态/布尔字段使用 TINYINT UNSIGNED 提高语义和效率 + * 3. 明确定义外键约束 (FK) + * 4. 关联表新增代理主键 (id),以支持 Mybatis-Plus 等 ORM 框架,并将原复合主键降级为 UNIQUE KEY。 + */ +-- 设置默认编码和排序规则 +-- USE chaos; -- 假设 chaos 数据库已存在且当前已选中 -- ---------------------------- -- 1. 系统用户表 (t_user) -- ---------------------------- -DROP TABLE IF EXISTS chaos.t_user; -CREATE TABLE chaos.t_user ( - id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID', - username VARCHAR(64) NOT NULL COMMENT '用户名/登录名', - password VARCHAR(255) NOT NULL COMMENT '密码(加密存储,建议BCrypt)', - nickname VARCHAR(64) DEFAULT '' COMMENT '用户昵称', - enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '状态 (1:启用, 0:禁用)', - account_non_expired TINYINT(1) NOT NULL DEFAULT 1 COMMENT '账号未过期 (1:是, 0:否)', - credentials_non_expired TINYINT(1) NOT NULL DEFAULT 1 COMMENT '凭证未过期 (1:是, 0:否)', - account_non_locked TINYINT(1) NOT NULL DEFAULT 1 COMMENT '账号未锁定 (1:是, 0:否)', - deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除 (1:已删除, 0:未删除)', - remark VARCHAR(500) DEFAULT '' COMMENT '备注信息', - create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - PRIMARY KEY (id), - UNIQUE KEY uk_username (username) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统管理-用户表'; +DROP TABLE IF EXISTS t_user; +CREATE TABLE t_user ( + id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID', + username VARCHAR(64) NOT NULL COMMENT '用户名/登录名', + password VARCHAR(255) NOT NULL COMMENT '密码(加密存储,建议BCrypt或Argon2)', + nickname VARCHAR(64) DEFAULT '' COMMENT '用户昵称', + enabled TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '状态 (1:启用, 0:禁用)', + account_non_expired TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '账号未过期 (1:是, 0:否)', + credentials_non_expired TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '凭证未过期 (1:是, 0:否)', + account_non_locked TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '账号未锁定 (1:是, 0:否)', + deleted TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '逻辑删除 (1:已删除, 0:未删除)', + remark VARCHAR(500) DEFAULT '' COMMENT '备注信息', + + -- 最佳实践: 自动维护时间戳 + create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + + PRIMARY KEY (id), + UNIQUE KEY uk_username (username) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统管理-用户表'; -- ---------------------------- -- 2. 角色/用户组表 (t_role) -- ---------------------------- -DROP TABLE IF EXISTS chaos.t_role; -CREATE TABLE chaos.t_role ( - id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID', - name VARCHAR(64) NOT NULL COMMENT '角色名称 (如: 管理员)', - code VARCHAR(64) NOT NULL COMMENT '角色标识 (如: admin)', - status TINYINT(1) NOT NULL DEFAULT 1 COMMENT '状态 (1:正常, 0:停用)', - remark VARCHAR(500) DEFAULT '' COMMENT '备注', - create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - PRIMARY KEY (id), - UNIQUE KEY uk_code (code) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统管理-角色表'; +DROP TABLE IF EXISTS t_role; +CREATE TABLE t_role ( + id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID', + name VARCHAR(64) NOT NULL COMMENT '角色名称 (如: 管理员)', + code VARCHAR(64) NOT NULL COMMENT '角色标识 (如: admin)', + status TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '状态 (1:正常, 0:停用)', + remark VARCHAR(500) DEFAULT '' COMMENT '备注', + + create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + + PRIMARY KEY (id), + UNIQUE KEY uk_code (code) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统管理-角色表'; -- ---------------------------- -- 3. 权限表 (t_permission) -- ---------------------------- -DROP TABLE IF EXISTS chaos.t_permission; -CREATE TABLE chaos.t_permission ( - id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID', - parent_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '父权限ID (0为顶级)', - name VARCHAR(64) NOT NULL COMMENT '权限名称', - code VARCHAR(128) NOT NULL COMMENT '权限标识/资源路径', - type TINYINT(1) NOT NULL DEFAULT 1 COMMENT '类型 (1:目录, 2:菜单, 3:按钮)', - sort_order INT NOT NULL DEFAULT 0 COMMENT '排序 (数值越小越靠前)', - create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - PRIMARY KEY (id), - UNIQUE KEY uk_code (code), - INDEX idx_parent_id (parent_id) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统管理-权限表'; +DROP TABLE IF EXISTS t_permission; +CREATE TABLE t_permission ( + id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID', + parent_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '父权限ID (0为顶级)', + name VARCHAR(64) NOT NULL COMMENT '权限名称', + code VARCHAR(128) NOT NULL COMMENT '权限标识/资源路径 (RESTful 风格或权限点)', + type TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '类型 (1:目录, 2:菜单, 3:按钮)', + sort_order INT NOT NULL DEFAULT 0 COMMENT '排序 (数值越小越靠前)', + + create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + + PRIMARY KEY (id), + UNIQUE KEY uk_code (code), + INDEX idx_parent_id (parent_id) -- 父节点查询优化 +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统管理-权限表'; -- ---------------------------- -- 4. 用户-角色关联表 (t_user_role) -- ---------------------------- -DROP TABLE IF EXISTS chaos.t_user_role; -CREATE TABLE chaos.t_user_role ( - user_id BIGINT UNSIGNED NOT NULL COMMENT '用户ID', - role_id BIGINT UNSIGNED NOT NULL COMMENT '角色ID', - PRIMARY KEY (user_id, role_id), - CONSTRAINT fk_ur_user_id FOREIGN KEY (user_id) REFERENCES chaos.t_user (id) ON DELETE CASCADE ON UPDATE CASCADE, - CONSTRAINT fk_ur_role_id FOREIGN KEY (role_id) REFERENCES chaos.t_role (id) ON DELETE CASCADE ON UPDATE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统管理-用户角色关联表'; +DROP TABLE IF EXISTS t_user_role; +CREATE TABLE t_user_role ( + id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID (代理键)', + user_id BIGINT UNSIGNED NOT NULL COMMENT '用户ID', + role_id BIGINT UNSIGNED NOT NULL COMMENT '角色ID', + + PRIMARY KEY (id), + UNIQUE KEY uk_user_role (user_id, role_id), -- 保持业务唯一性约束 + + -- 外键约束: 引用 t_user.id + CONSTRAINT fk_ur_user_id FOREIGN KEY (user_id) REFERENCES t_user (id) ON DELETE CASCADE ON UPDATE CASCADE, + -- 外键约束: 引用 t_role.id + CONSTRAINT fk_ur_role_id FOREIGN KEY (role_id) REFERENCES t_role (id) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统管理-用户角色关联表'; -- ---------------------------- -- 5. 角色-权限关联表 (t_role_permission) -- ---------------------------- -DROP TABLE IF EXISTS chaos.t_role_permission; -CREATE TABLE chaos.t_role_permission ( - role_id BIGINT UNSIGNED NOT NULL COMMENT '角色ID', - permission_id BIGINT UNSIGNED NOT NULL COMMENT '权限ID', - PRIMARY KEY (role_id, permission_id), - CONSTRAINT fk_rp_role_id FOREIGN KEY (role_id) REFERENCES chaos.t_role (id) ON DELETE CASCADE ON UPDATE CASCADE, - CONSTRAINT fk_rp_permission_id FOREIGN KEY (permission_id) REFERENCES chaos.t_permission (id) ON DELETE CASCADE ON UPDATE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统管理-角色权限关联表'; +DROP TABLE IF EXISTS t_role_permission; +CREATE TABLE t_role_permission ( + id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID (代理键)', + role_id BIGINT UNSIGNED NOT NULL COMMENT '角色ID', + permission_id BIGINT UNSIGNED NOT NULL COMMENT '权限ID', + + PRIMARY KEY (id), + UNIQUE KEY uk_role_permission (role_id, permission_id), -- 保持业务唯一性约束 + + -- 外键约束: 引用 t_role.id + CONSTRAINT fk_rp_role_id FOREIGN KEY (role_id) REFERENCES t_role (id) ON DELETE CASCADE ON UPDATE CASCADE, + -- 外键约束: 引用 t_permission.id + CONSTRAINT fk_rp_permission_id FOREIGN KEY (permission_id) REFERENCES t_permission (id) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统管理-角色权限关联表'; -- ---------------------------- -- 6. 基础设备表 (t_device) -- ---------------------------- -DROP TABLE IF EXISTS chaos.t_device; -CREATE TABLE chaos.t_device ( - id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID', - name VARCHAR(128) NOT NULL COMMENT '设备名称', - model VARCHAR(128) DEFAULT NULL COMMENT '设备型号', - type_id BIGINT UNSIGNED DEFAULT NULL COMMENT '设备类型ID (关联类型表)', - location_id BIGINT UNSIGNED DEFAULT NULL COMMENT '位置ID (关联位置表)', - snmp_community VARCHAR(128) DEFAULT NULL COMMENT 'SNMP团体名 (加密存储建议)', - manufacturer VARCHAR(128) DEFAULT NULL COMMENT '设备制造商', - purchase_date DATE DEFAULT NULL COMMENT '采购日期', - status TINYINT DEFAULT 1 COMMENT '设备状态 (1:在线, 0:离线, 2:维护中)', - remark VARCHAR(500) DEFAULT '' COMMENT '备注', - create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - PRIMARY KEY (id), - INDEX idx_type_id (type_id), - INDEX idx_location_id (location_id) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='资产管理-设备信息表'; +DROP TABLE IF EXISTS t_device; +CREATE TABLE t_device ( + id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID', + name VARCHAR(128) NOT NULL COMMENT '设备名称', + model VARCHAR(128) DEFAULT NULL COMMENT '设备型号', + type_id BIGINT UNSIGNED DEFAULT NULL COMMENT '设备类型ID (外键关联设备类型表)', + location_id BIGINT UNSIGNED DEFAULT NULL COMMENT '位置ID (外键关联位置表)', + snmp_community VARCHAR(128) DEFAULT NULL COMMENT 'SNMP团体名 (建议加密或隐藏)', + manufacturer VARCHAR(128) DEFAULT NULL COMMENT '设备制造商', + purchase_date DATE DEFAULT NULL COMMENT '采购日期', + status TINYINT UNSIGNED DEFAULT 1 COMMENT '设备状态 (1:在线, 0:离线, 2:维护中)', + remark VARCHAR(500) DEFAULT '' COMMENT '备注', + + create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + + PRIMARY KEY (id), + INDEX idx_type_id (type_id), + INDEX idx_location_id (location_id) + -- 注意: 如果 t_device_type 和 t_location 表存在,需要在此处添加相应的 FOREIGN KEY 约束 +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='资产管理-设备信息表'; -- ---------------------------- -- 7. 网络接口表 (t_network_interface) -- ---------------------------- -DROP TABLE IF EXISTS chaos.t_network_interface; -CREATE TABLE chaos.t_network_interface ( - id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID', - device_id BIGINT UNSIGNED NOT NULL COMMENT '设备ID', - parent_id BIGINT UNSIGNED DEFAULT NULL COMMENT '父接口ID (用于子接口/聚合口)', - name VARCHAR(64) NOT NULL COMMENT '接口名称 (如: eth0, GE0/0/1)', - mac_address VARCHAR(17) DEFAULT NULL COMMENT 'MAC地址 (格式: AA:BB:CC:DD:EE:FF)', - ip_address VARCHAR(45) DEFAULT NULL COMMENT 'IP地址 (支持IPv4/IPv6)', - subnet_mask VARCHAR(45) DEFAULT NULL COMMENT '子网掩码/前缀长度', - gateway_ip VARCHAR(45) DEFAULT NULL COMMENT '网关IP地址', - vlan_id INT DEFAULT NULL COMMENT 'VLAN ID (1-4094)', - port_speed INT DEFAULT 0 COMMENT '端口速率 (Mbps)', - status TINYINT DEFAULT 1 COMMENT '接口状态 (1:UP, 0:DOWN)', - remark VARCHAR(500) DEFAULT '' COMMENT '备注', - create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - PRIMARY KEY (id), - CONSTRAINT fk_ni_device_id FOREIGN KEY (device_id) REFERENCES chaos.t_device (id) ON DELETE CASCADE ON UPDATE CASCADE, - CONSTRAINT fk_ni_parent_id FOREIGN KEY (parent_id) REFERENCES chaos.t_network_interface (id) ON DELETE SET NULL ON UPDATE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='资产管理-网络接口表'; \ No newline at end of file +DROP TABLE IF EXISTS t_network_interface; +CREATE TABLE t_network_interface ( + id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID', + device_id BIGINT UNSIGNED NOT NULL COMMENT '设备ID', + parent_id BIGINT UNSIGNED DEFAULT NULL COMMENT '父接口ID (用于子接口/聚合口,自关联)', + name VARCHAR(64) NOT NULL COMMENT '接口名称 (如: eth0, GE0/0/1)', + mac_address VARCHAR(17) DEFAULT NULL COMMENT 'MAC地址 (格式: AA:BB:CC:DD:EE:FF)', + ip_address VARCHAR(45) DEFAULT NULL COMMENT 'IP地址 (支持IPv4/IPv6)', + subnet_mask VARCHAR(45) DEFAULT NULL COMMENT '子网掩码/前缀长度', + gateway_ip VARCHAR(45) DEFAULT NULL COMMENT '网关IP地址', + vlan_id SMALLINT UNSIGNED DEFAULT NULL COMMENT 'VLAN ID (1-4094, SMALLINT更合适)', + port_speed INT UNSIGNED DEFAULT 0 COMMENT '端口速率 (Mbps)', + status TINYINT UNSIGNED DEFAULT 1 COMMENT '接口状态 (1:UP, 0:DOWN)', + remark VARCHAR(500) DEFAULT '' COMMENT '备注', + + create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + + PRIMARY KEY (id), + INDEX idx_mac_address (mac_address), + INDEX idx_ip_address (ip_address), + -- 外键约束: 引用 t_device.id + CONSTRAINT fk_ni_device_id FOREIGN KEY (device_id) REFERENCES t_device (id) ON DELETE CASCADE ON UPDATE CASCADE, + -- 外键约束: 引用自身 (自关联) + CONSTRAINT fk_ni_parent_id FOREIGN KEY (parent_id) REFERENCES t_network_interface (id) ON DELETE SET NULL ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='资产管理-网络接口表'; \ No newline at end of file