2. 数据库设计与用户模块:用户表、角色表、权限表

好,咱们进入第二章。这一章很关键,说白了就是给整个OA系统打地基。数据库设计要是歪了,后面盖多少层楼都得塌。我个人习惯,在写一行代码之前,先把表结构理清楚。你想想看,用户、角色、权限这三张表,几乎是所有企业级应用的标配。

2.1 用户表设计:别只存个用户名

用户表是最基础的。但我见过太多新手,上来就只弄个usernamepassword。嗯,这在OA系统里根本不够用。你得考虑:用户叫什么?手机号多少?头像要不要?状态是启用还是禁用?

我在项目中遇到过最坑的事,就是一开始没留deleted字段。后来要搞软删除,不得不改表结构,还影响了线上数据。所以,我建议你从一开始就把这些字段都加上。

字段名 类型 说明
id bigint 主键,自增
username varchar(50) 登录名,唯一
password varchar(255) 加密后的密码
real_name varchar(50) 真实姓名
phone varchar(20) 手机号
email varchar(100) 邮箱
avatar varchar(255) 头像URL
status tinyint 0禁用 1启用
deleted tinyint 0未删 1已删
create_time datetime 创建时间
update_time datetime 更新时间
我的小技巧:密码字段长度设255,别问为什么。因为加密算法迭代后,哈希值长度可能会变。我曾经用varchar(60)存bcrypt,后来升级算法就炸了。

2.2 角色表设计:权限的集合体

角色是什么?说白了就是一堆权限的打包。比如「管理员」角色,可能包含「创建用户」、「删除用户」、「查看报表」等权限。而「普通员工」角色,就只有「查看自己的信息」、「提交请假」这些。

角色表本身很简单,但要注意一点:角色和用户是多对多的关系。一个用户可以有多个角色,一个角色也可以属于多个用户。所以我们需要一张中间表。

字段名 类型 说明
id bigint 主键
role_name varchar(50) 角色名称,如"管理员"
role_code varchar(50) 角色编码,如"ADMIN"
description varchar(255) 角色描述
status tinyint 0禁用 1启用
重点:role_code是给程序用的,role_name是给人看的。千万别混用。我见过有人直接用中文角色名做判断,结果换了个环境就全乱了。

2.3 权限表设计:细到按钮级别

权限表,这是整个权限系统的核心。很多小系统只做到「菜单权限」,就是能看到哪些页面。但OA系统往往需要更细的控制——比如「用户管理」页面里的「新增」按钮,能不能点?

我建议把权限设计成树形结构。举个例子:

  • 系统管理(菜单权限)
    • 用户管理(页面权限)
      • 新增用户(按钮权限)
      • 编辑用户(按钮权限)
      • 删除用户(按钮权限)
    • 角色管理(页面权限)
      • 分配权限(按钮权限)
字段名 类型 说明
id bigint 主键
perm_name varchar(50) 权限名称
perm_code varchar(100) 权限编码,如"user:add"
parent_id bigint 父权限ID,0表示顶级
type tinyint 1菜单 2页面 3按钮
sort int 排序号
status tinyint 0禁用 1启用
避坑指南:我曾经把权限编码设计成纯数字ID,结果后来要对接第三方系统,人家要求用字符串标识。改得我头皮发麻。所以,从一开始就用有意义的字符串编码,比如"user:add"、"report:view"。

2.4 数据库初始化脚本编写

好了,表结构设计完了,接下来就是写SQL脚本。我习惯把建表语句、初始数据、索引都放在一个文件里,方便部署时一键执行。

-- 用户表
CREATE TABLE `sys_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL COMMENT '登录名',
  `password` varchar(255) NOT NULL COMMENT '密码',
  `real_name` varchar(50) DEFAULT NULL COMMENT '真实姓名',
  `phone` varchar(20) DEFAULT NULL COMMENT '手机号',
  `email` varchar(100) DEFAULT NULL COMMENT '邮箱',
  `avatar` varchar(255) DEFAULT NULL COMMENT '头像',
  `status` tinyint(4) DEFAULT '1' COMMENT '0禁用 1启用',
  `deleted` tinyint(4) DEFAULT '0' COMMENT '0未删 1已删',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

-- 角色表
CREATE TABLE `sys_role` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `role_name` varchar(50) NOT NULL COMMENT '角色名称',
  `role_code` varchar(50) NOT NULL COMMENT '角色编码',
  `description` varchar(255) DEFAULT NULL COMMENT '描述',
  `status` tinyint(4) DEFAULT '1' COMMENT '0禁用 1启用',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_role_code` (`role_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表';

-- 权限表
CREATE TABLE `sys_permission` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `perm_name` varchar(50) NOT NULL COMMENT '权限名称',
  `perm_code` varchar(100) NOT NULL COMMENT '权限编码',
  `parent_id` bigint(20) DEFAULT '0' COMMENT '父权限ID',
  `type` tinyint(4) DEFAULT '1' COMMENT '1菜单 2页面 3按钮',
  `sort` int(11) DEFAULT '0' COMMENT '排序号',
  `status` tinyint(4) DEFAULT '1' COMMENT '0禁用 1启用',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_perm_code` (`perm_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限表';

-- 用户角色关联表
CREATE TABLE `sys_user_role` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) NOT NULL,
  `role_id` bigint(20) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_user_id` (`user_id`),
  KEY `idx_role_id` (`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户角色关联表';

-- 角色权限关联表
CREATE TABLE `sys_role_permission` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `role_id` bigint(20) NOT NULL,
  `perm_id` bigint(20) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_role_id` (`role_id`),
  KEY `idx_perm_id` (`perm_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色权限关联表';

-- 插入初始数据
INSERT INTO `sys_role` (`role_name`, `role_code`, `description`) VALUES
('超级管理员', 'SUPER_ADMIN', '拥有所有权限'),
('普通用户', 'USER', '基础用户权限');

INSERT INTO `sys_user` (`username`, `password`, `real_name`, `status`) VALUES
('admin', '$2a$10$...', '系统管理员', 1);
说个经验:密码字段里存的是加密后的字符串,千万别存明文。我一般用BCrypt加密,安全系数高。初始密码可以统一设为"123456",上线前让用户改掉就行。

嗯,到这里,数据库设计这块就差不多了。你可能会问:「为什么用户和角色之间要加一张关联表?」其实原因很简单——为了灵活。如果用户只能有一个角色,那直接在用户表加个role_id字段就行了。但现实是,一个人可能既是「部门经理」又是「项目管理员」,多对多的关系必须用中间表。

下一章,咱们开始写代码。我会带着你从零搭建项目骨架,把Spring Boot项目跑起来。到时候这些表就会真正「活」过来。