feat(database): 重构用户角色关联及权限体系
- 新增 BizException 构造函数支持自定义消息 - 优化 SQL 脚本结构,明确表设计最佳实践 - 修改 t_user、t_role 等表字段类型与索引策略 - 引入代理主键 id 到关联表 t_user_role 和 t_role_permission - 更新 UserRole 实体类适配 MyBatis-Plus 主键策略 - 增强 UserRoleService 接口功能,支持分配和撤销角色 - 实现批量操作和事务控制提升数据一致性 - 添加安全注解 @PreAuthorize 控制接口访问权限 - 修正 Mapper 注解并优化参数命名提高可读性 - 扩展 ErrorCode 常量增强错误描述准确性
This commit is contained in:
@@ -30,9 +30,12 @@ public enum ErrorCode {
|
|||||||
PHONE_EXISTS(409, "USER-109", "手机号已注册"),
|
PHONE_EXISTS(409, "USER-109", "手机号已注册"),
|
||||||
PHONE_FORMAT_ERROR(400, "USER-110", "手机号格式无效"),
|
PHONE_FORMAT_ERROR(400, "USER-110", "手机号格式无效"),
|
||||||
USER_UPDATE_USERNAME_FAILED(400,"USER-111" , "用户名更新失败"),
|
USER_UPDATE_USERNAME_FAILED(400,"USER-111" , "用户名更新失败"),
|
||||||
|
// 用户组
|
||||||
|
ROLE_REVOKE_FAILED(400,"USER-112" ,"用户组删除失败" ),
|
||||||
|
|
||||||
|
ROLE_ID_EXISTS(400, "ROLE-100" , "角色ID已存在" ),
|
||||||
ROLE_ID_INVALID(400, "ROLE-100" , "角色ID无效" ),
|
ROLE_ID_INVALID(400, "ROLE-101" , "角色ID无效" ),
|
||||||
|
ROLE_ID_NOT_EXISTS(400, "ROLE-102" , "角色ID不存在"),
|
||||||
|
|
||||||
// ================== 论坛内容相关 (200-299) ==================
|
// ================== 论坛内容相关 (200-299) ==================
|
||||||
POST_NOT_FOUND(404, "POST-201", "帖子不存在"),
|
POST_NOT_FOUND(404, "POST-201", "帖子不存在"),
|
||||||
@@ -47,7 +50,7 @@ public enum ErrorCode {
|
|||||||
CAPTCHA_ERROR(400, "SYS-301", "验证码错误"),
|
CAPTCHA_ERROR(400, "SYS-301", "验证码错误"),
|
||||||
SMS_SEND_FAILED(500, "SYS-302", "短信发送失败"),
|
SMS_SEND_FAILED(500, "SYS-302", "短信发送失败"),
|
||||||
FILE_UPLOAD_FAILED(500, "SYS-303", "文件上传失败"),
|
FILE_UPLOAD_FAILED(500, "SYS-303", "文件上传失败"),
|
||||||
RATE_LIMIT_EXCEEDED(429, "SYS-304", "操作过于频繁"),;
|
RATE_LIMIT_EXCEEDED(429, "SYS-304", "操作过于频繁");
|
||||||
|
|
||||||
private final int httpStatus;
|
private final int httpStatus;
|
||||||
private final String code; // 业务错误码(领域-编号)
|
private final String code; // 业务错误码(领域-编号)
|
||||||
|
|||||||
@@ -11,4 +11,8 @@ public class BizException extends RuntimeException{
|
|||||||
super(errorCode.getMessage());
|
super(errorCode.getMessage());
|
||||||
this.errorCode = errorCode;
|
this.errorCode = errorCode;
|
||||||
}
|
}
|
||||||
|
public BizException(String message) {
|
||||||
|
super(message);
|
||||||
|
this.errorCode = ErrorCode.SYSTEM_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,12 +32,13 @@ public interface UserMapper extends BaseMapper<User> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 插入用户角色关系
|
* 插入用户角色关系
|
||||||
* @param id 用户id
|
* 注意:已将注解由 @Select 修正为 @Insert,并优化了参数命名。
|
||||||
* @param i 角色id
|
* 由于 t_user_role 现在有自增主键 id,只需插入 user_id 和 role_id。
|
||||||
|
* @param userId 用户id
|
||||||
|
* @param roleId 角色id
|
||||||
*/
|
*/
|
||||||
|
@Insert("INSERT INTO t_user_role (user_id, role_id) VALUES (#{userId}, #{roleId})")
|
||||||
@Select("INSERT INTO t_user_role (user_id, role_id) VALUES (#{userId}, #{roleId})")
|
void insertUserRole(@Param("userId") Long userId, @Param("roleId") Long roleId);
|
||||||
void insertUserRole(@Param("userId") Long id, @Param("roleId") Long i);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据用户名查询用户信息
|
* 根据用户名查询用户信息
|
||||||
|
|||||||
@@ -2,6 +2,17 @@ package cn.nopj.chaos_api.mapper;
|
|||||||
|
|
||||||
import cn.nopj.chaos_api.domain.entity.UserRole;
|
import cn.nopj.chaos_api.domain.entity.UserRole;
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
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<UserRole> {
|
public interface UserRoleMapper extends BaseMapper<UserRole> {
|
||||||
|
/**
|
||||||
|
* 删除用户角色关系
|
||||||
|
* @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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
package cn.nopj.chaos_api.domain.entity;
|
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 com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
@TableName("t_user_role")
|
@TableName("t_user_role")
|
||||||
@AllArgsConstructor
|
@Data
|
||||||
@NoArgsConstructor
|
|
||||||
public class UserRole {
|
public class UserRole {
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Long id; // 虚拟字段,数据库可不存
|
||||||
|
|
||||||
private Long userId;
|
private Long userId;
|
||||||
private Long roleId;
|
private Long roleId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,16 +8,16 @@ import java.util.List;
|
|||||||
* 用户角色服务
|
* 用户角色服务
|
||||||
*/
|
*/
|
||||||
public interface UserRoleService {
|
public interface UserRoleService {
|
||||||
/**
|
|
||||||
* 为用户设置角色
|
|
||||||
* @param userId 用户id
|
|
||||||
* @param roles_id 角色id组
|
|
||||||
*/
|
|
||||||
void setUserRole(Long userId, List<Long> roles_id);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 为用户设置角色
|
* 为用户设置角色
|
||||||
* @param request 请求参数
|
* @param request 请求参数
|
||||||
*/
|
*/
|
||||||
void setUserRole(SetUserRoleRequest request);
|
void assignRolesToUser(SetUserRoleRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消用户角色
|
||||||
|
* @param request 角色id组
|
||||||
|
*/
|
||||||
|
int revokeRolesFromUser(SetUserRoleRequest request);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.dto.request.SetUserRoleRequest;
|
||||||
import cn.nopj.chaos_api.mapper.UserRoleMapper;
|
import cn.nopj.chaos_api.mapper.UserRoleMapper;
|
||||||
import cn.nopj.chaos_api.service.UserRoleService;
|
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 lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class UserRoleServiceImpl implements UserRoleService {
|
// 继承 ServiceImpl<UserRoleMapper, UserRole> 以获得批量操作能力
|
||||||
|
public class UserRoleServiceImpl extends ServiceImpl<UserRoleMapper, UserRole> implements UserRoleService {
|
||||||
|
|
||||||
@Autowired
|
/**
|
||||||
private UserRoleMapper userRoleMapper;
|
* 批量分配角色给用户。
|
||||||
|
*/
|
||||||
@Override
|
|
||||||
|
|
||||||
public void setUserRole(Long userId, List<Long> roles_id) {
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@Override
|
@Override
|
||||||
public void setUserRole(SetUserRoleRequest request) {
|
public void assignRolesToUser(SetUserRoleRequest request) {
|
||||||
if (request == null || request.getUserId() == null ){
|
if (request == null || request.getUserId() == null || request.getUserId() <= 0L){
|
||||||
|
throw new BizException(ErrorCode.USER_ID_INVALID);
|
||||||
|
}
|
||||||
|
Long userId = request.getUserId();
|
||||||
|
|
||||||
|
if (request.getRolesId() == null || request.getRolesId().isEmpty()){
|
||||||
|
this.baseMapper.delete(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId,userId));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Long> 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<UserRole> 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<UserRole>().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 int revokeRolesFromUser(SetUserRoleRequest request) {
|
||||||
|
if (request == null || request.getUserId() == null || request.getUserId() <= 0L){
|
||||||
throw new BizException(ErrorCode.USER_ID_INVALID);
|
throw new BizException(ErrorCode.USER_ID_INVALID);
|
||||||
}
|
}
|
||||||
if (request.getRolesId() == null || request.getRolesId().isEmpty()){
|
if (request.getRolesId() == null || request.getRolesId().isEmpty()){
|
||||||
@@ -44,7 +94,22 @@ public class UserRoleServiceImpl implements UserRoleService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Long userId = request.getUserId();
|
Long userId = request.getUserId();
|
||||||
List<Long> roles_id = request.getRolesId();
|
List<Long> rolesId = request.getRolesId();
|
||||||
setUserRole(userId, roles_id);
|
|
||||||
|
|
||||||
|
LambdaQueryWrapper<UserRole> 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@ import cn.nopj.chaos_api.model.ApiResult;
|
|||||||
import cn.nopj.chaos_api.service.UserRoleService;
|
import cn.nopj.chaos_api.service.UserRoleService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
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.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
@@ -28,9 +29,20 @@ public class RoleController {
|
|||||||
* @param request 请求参数
|
* @param request 请求参数
|
||||||
* @return 处理结果
|
* @return 处理结果
|
||||||
*/
|
*/
|
||||||
|
@PreAuthorize("hasAuthority('admin')")
|
||||||
@RequestMapping("/setUserRole")
|
@RequestMapping("/setUserRole")
|
||||||
public ApiResult<String> setUserRole(@RequestBody SetUserRoleRequest request) {
|
public ApiResult<String> setUserRole(@RequestBody SetUserRoleRequest request) {
|
||||||
userRoleService.setUserRole(request);
|
userRoleService.assignRolesToUser(request);
|
||||||
return ApiResult.success("用户角色设置成功");
|
return ApiResult.success("用户角色设置成功");
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 取消用户角色
|
||||||
|
* @param request 请求参数
|
||||||
|
* @return 处理结果
|
||||||
|
*/
|
||||||
|
@PreAuthorize("hasAuthority('admin')")
|
||||||
|
@RequestMapping("/cancelUserRole")
|
||||||
|
public ApiResult<?> cancelUserRole(@RequestBody SetUserRoleRequest request) {
|
||||||
|
return ApiResult.success("用户角色取消成功",userRoleService.revokeRolesFromUser(request));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
-- 1. 系统用户表 (t_user)
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS chaos.t_user;
|
DROP TABLE IF EXISTS t_user;
|
||||||
CREATE TABLE chaos.t_user (
|
CREATE TABLE t_user (
|
||||||
id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID',
|
id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID',
|
||||||
username VARCHAR(64) NOT NULL COMMENT '用户名/登录名',
|
username VARCHAR(64) NOT NULL COMMENT '用户名/登录名',
|
||||||
password VARCHAR(255) NOT NULL COMMENT '密码(加密存储,建议BCrypt)',
|
password VARCHAR(255) NOT NULL COMMENT '密码(加密存储,建议BCrypt或Argon2)',
|
||||||
nickname VARCHAR(64) DEFAULT '' COMMENT '用户昵称',
|
nickname VARCHAR(64) DEFAULT '' COMMENT '用户昵称',
|
||||||
enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '状态 (1:启用, 0:禁用)',
|
enabled TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '状态 (1:启用, 0:禁用)',
|
||||||
account_non_expired TINYINT(1) NOT NULL DEFAULT 1 COMMENT '账号未过期 (1:是, 0:否)',
|
account_non_expired TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '账号未过期 (1:是, 0:否)',
|
||||||
credentials_non_expired TINYINT(1) NOT NULL DEFAULT 1 COMMENT '凭证未过期 (1:是, 0:否)',
|
credentials_non_expired TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '凭证未过期 (1:是, 0:否)',
|
||||||
account_non_locked TINYINT(1) NOT NULL DEFAULT 1 COMMENT '账号未锁定 (1:是, 0:否)',
|
account_non_locked TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '账号未锁定 (1:是, 0:否)',
|
||||||
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除 (1:已删除, 0:未删除)',
|
deleted TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '逻辑删除 (1:已删除, 0:未删除)',
|
||||||
remark VARCHAR(500) DEFAULT '' COMMENT '备注信息',
|
remark VARCHAR(500) DEFAULT '' COMMENT '备注信息',
|
||||||
|
|
||||||
|
-- 最佳实践: 自动维护时间戳
|
||||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id),
|
||||||
UNIQUE KEY uk_username (username)
|
UNIQUE KEY uk_username (username)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统管理-用户表';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统管理-用户表';
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- 2. 角色/用户组表 (t_role)
|
-- 2. 角色/用户组表 (t_role)
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS chaos.t_role;
|
DROP TABLE IF EXISTS t_role;
|
||||||
CREATE TABLE chaos.t_role (
|
CREATE TABLE t_role (
|
||||||
id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID',
|
id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID',
|
||||||
name VARCHAR(64) NOT NULL COMMENT '角色名称 (如: 管理员)',
|
name VARCHAR(64) NOT NULL COMMENT '角色名称 (如: 管理员)',
|
||||||
code VARCHAR(64) NOT NULL COMMENT '角色标识 (如: admin)',
|
code VARCHAR(64) NOT NULL COMMENT '角色标识 (如: admin)',
|
||||||
status TINYINT(1) NOT NULL DEFAULT 1 COMMENT '状态 (1:正常, 0:停用)',
|
status TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '状态 (1:正常, 0:停用)',
|
||||||
remark VARCHAR(500) DEFAULT '' COMMENT '备注',
|
remark VARCHAR(500) DEFAULT '' COMMENT '备注',
|
||||||
|
|
||||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id),
|
||||||
UNIQUE KEY uk_code (code)
|
UNIQUE KEY uk_code (code)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统管理-角色表';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统管理-角色表';
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- 3. 权限表 (t_permission)
|
-- 3. 权限表 (t_permission)
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS chaos.t_permission;
|
DROP TABLE IF EXISTS t_permission;
|
||||||
CREATE TABLE chaos.t_permission (
|
CREATE TABLE t_permission (
|
||||||
id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID',
|
id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID',
|
||||||
parent_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '父权限ID (0为顶级)',
|
parent_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '父权限ID (0为顶级)',
|
||||||
name VARCHAR(64) NOT NULL COMMENT '权限名称',
|
name VARCHAR(64) NOT NULL COMMENT '权限名称',
|
||||||
code VARCHAR(128) NOT NULL COMMENT '权限标识/资源路径',
|
code VARCHAR(128) NOT NULL COMMENT '权限标识/资源路径 (RESTful 风格或权限点)',
|
||||||
type TINYINT(1) NOT NULL DEFAULT 1 COMMENT '类型 (1:目录, 2:菜单, 3:按钮)',
|
type TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '类型 (1:目录, 2:菜单, 3:按钮)',
|
||||||
sort_order INT NOT NULL DEFAULT 0 COMMENT '排序 (数值越小越靠前)',
|
sort_order INT NOT NULL DEFAULT 0 COMMENT '排序 (数值越小越靠前)',
|
||||||
|
|
||||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id),
|
||||||
UNIQUE KEY uk_code (code),
|
UNIQUE KEY uk_code (code),
|
||||||
INDEX idx_parent_id (parent_id)
|
INDEX idx_parent_id (parent_id) -- 父节点查询优化
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统管理-权限表';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统管理-权限表';
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- 4. 用户-角色关联表 (t_user_role)
|
-- 4. 用户-角色关联表 (t_user_role)
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS chaos.t_user_role;
|
DROP TABLE IF EXISTS t_user_role;
|
||||||
CREATE TABLE chaos.t_user_role (
|
CREATE TABLE t_user_role (
|
||||||
|
id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID (代理键)',
|
||||||
user_id BIGINT UNSIGNED NOT NULL COMMENT '用户ID',
|
user_id BIGINT UNSIGNED NOT NULL COMMENT '用户ID',
|
||||||
role_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,
|
PRIMARY KEY (id),
|
||||||
CONSTRAINT fk_ur_role_id FOREIGN KEY (role_id) REFERENCES chaos.t_role (id) ON DELETE CASCADE ON UPDATE CASCADE
|
UNIQUE KEY uk_user_role (user_id, role_id), -- 保持业务唯一性约束
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统管理-用户角色关联表';
|
|
||||||
|
-- 外键约束: 引用 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)
|
-- 5. 角色-权限关联表 (t_role_permission)
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS chaos.t_role_permission;
|
DROP TABLE IF EXISTS t_role_permission;
|
||||||
CREATE TABLE chaos.t_role_permission (
|
CREATE TABLE t_role_permission (
|
||||||
|
id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID (代理键)',
|
||||||
role_id BIGINT UNSIGNED NOT NULL COMMENT '角色ID',
|
role_id BIGINT UNSIGNED NOT NULL COMMENT '角色ID',
|
||||||
permission_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,
|
PRIMARY KEY (id),
|
||||||
CONSTRAINT fk_rp_permission_id FOREIGN KEY (permission_id) REFERENCES chaos.t_permission (id) ON DELETE CASCADE ON UPDATE CASCADE
|
UNIQUE KEY uk_role_permission (role_id, permission_id), -- 保持业务唯一性约束
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统管理-角色权限关联表';
|
|
||||||
|
-- 外键约束: 引用 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)
|
-- 6. 基础设备表 (t_device)
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS chaos.t_device;
|
DROP TABLE IF EXISTS t_device;
|
||||||
CREATE TABLE chaos.t_device (
|
CREATE TABLE t_device (
|
||||||
id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID',
|
id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID',
|
||||||
name VARCHAR(128) NOT NULL COMMENT '设备名称',
|
name VARCHAR(128) NOT NULL COMMENT '设备名称',
|
||||||
model VARCHAR(128) DEFAULT NULL COMMENT '设备型号',
|
model VARCHAR(128) DEFAULT NULL COMMENT '设备型号',
|
||||||
type_id BIGINT UNSIGNED DEFAULT NULL COMMENT '设备类型ID (关联类型表)',
|
type_id BIGINT UNSIGNED DEFAULT NULL COMMENT '设备类型ID (外键关联设备类型表)',
|
||||||
location_id BIGINT UNSIGNED DEFAULT NULL COMMENT '位置ID (关联位置表)',
|
location_id BIGINT UNSIGNED DEFAULT NULL COMMENT '位置ID (外键关联位置表)',
|
||||||
snmp_community VARCHAR(128) DEFAULT NULL COMMENT 'SNMP团体名 (加密存储建议)',
|
snmp_community VARCHAR(128) DEFAULT NULL COMMENT 'SNMP团体名 (建议加密或隐藏)',
|
||||||
manufacturer VARCHAR(128) DEFAULT NULL COMMENT '设备制造商',
|
manufacturer VARCHAR(128) DEFAULT NULL COMMENT '设备制造商',
|
||||||
purchase_date DATE DEFAULT NULL COMMENT '采购日期',
|
purchase_date DATE DEFAULT NULL COMMENT '采购日期',
|
||||||
status TINYINT DEFAULT 1 COMMENT '设备状态 (1:在线, 0:离线, 2:维护中)',
|
status TINYINT UNSIGNED DEFAULT 1 COMMENT '设备状态 (1:在线, 0:离线, 2:维护中)',
|
||||||
remark VARCHAR(500) DEFAULT '' COMMENT '备注',
|
remark VARCHAR(500) DEFAULT '' COMMENT '备注',
|
||||||
|
|
||||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id),
|
||||||
INDEX idx_type_id (type_id),
|
INDEX idx_type_id (type_id),
|
||||||
INDEX idx_location_id (location_id)
|
INDEX idx_location_id (location_id)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='资产管理-设备信息表';
|
-- 注意: 如果 t_device_type 和 t_location 表存在,需要在此处添加相应的 FOREIGN KEY 约束
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='资产管理-设备信息表';
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- 7. 网络接口表 (t_network_interface)
|
-- 7. 网络接口表 (t_network_interface)
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS chaos.t_network_interface;
|
DROP TABLE IF EXISTS t_network_interface;
|
||||||
CREATE TABLE chaos.t_network_interface (
|
CREATE TABLE t_network_interface (
|
||||||
id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID',
|
id BIGINT UNSIGNED AUTO_INCREMENT COMMENT '主键ID',
|
||||||
device_id BIGINT UNSIGNED NOT NULL COMMENT '设备ID',
|
device_id BIGINT UNSIGNED NOT NULL COMMENT '设备ID',
|
||||||
parent_id BIGINT UNSIGNED DEFAULT NULL COMMENT '父接口ID (用于子接口/聚合口)',
|
parent_id BIGINT UNSIGNED DEFAULT NULL COMMENT '父接口ID (用于子接口/聚合口,自关联)',
|
||||||
name VARCHAR(64) NOT NULL COMMENT '接口名称 (如: eth0, GE0/0/1)',
|
name VARCHAR(64) NOT NULL COMMENT '接口名称 (如: eth0, GE0/0/1)',
|
||||||
mac_address VARCHAR(17) DEFAULT NULL COMMENT 'MAC地址 (格式: AA:BB:CC:DD:EE:FF)',
|
mac_address VARCHAR(17) DEFAULT NULL COMMENT 'MAC地址 (格式: AA:BB:CC:DD:EE:FF)',
|
||||||
ip_address VARCHAR(45) DEFAULT NULL COMMENT 'IP地址 (支持IPv4/IPv6)',
|
ip_address VARCHAR(45) DEFAULT NULL COMMENT 'IP地址 (支持IPv4/IPv6)',
|
||||||
subnet_mask VARCHAR(45) DEFAULT NULL COMMENT '子网掩码/前缀长度',
|
subnet_mask VARCHAR(45) DEFAULT NULL COMMENT '子网掩码/前缀长度',
|
||||||
gateway_ip VARCHAR(45) DEFAULT NULL COMMENT '网关IP地址',
|
gateway_ip VARCHAR(45) DEFAULT NULL COMMENT '网关IP地址',
|
||||||
vlan_id INT DEFAULT NULL COMMENT 'VLAN ID (1-4094)',
|
vlan_id SMALLINT UNSIGNED DEFAULT NULL COMMENT 'VLAN ID (1-4094, SMALLINT更合适)',
|
||||||
port_speed INT DEFAULT 0 COMMENT '端口速率 (Mbps)',
|
port_speed INT UNSIGNED DEFAULT 0 COMMENT '端口速率 (Mbps)',
|
||||||
status TINYINT DEFAULT 1 COMMENT '接口状态 (1:UP, 0:DOWN)',
|
status TINYINT UNSIGNED DEFAULT 1 COMMENT '接口状态 (1:UP, 0:DOWN)',
|
||||||
remark VARCHAR(500) DEFAULT '' COMMENT '备注',
|
remark VARCHAR(500) DEFAULT '' COMMENT '备注',
|
||||||
|
|
||||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id),
|
||||||
CONSTRAINT fk_ni_device_id FOREIGN KEY (device_id) REFERENCES chaos.t_device (id) ON DELETE CASCADE ON UPDATE CASCADE,
|
INDEX idx_mac_address (mac_address),
|
||||||
CONSTRAINT fk_ni_parent_id FOREIGN KEY (parent_id) REFERENCES chaos.t_network_interface (id) ON DELETE SET NULL ON UPDATE CASCADE
|
INDEX idx_ip_address (ip_address),
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='资产管理-网络接口表';
|
-- 外键约束: 引用 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='资产管理-网络接口表';
|
||||||
Reference in New Issue
Block a user