2、后端项目初始化与数据库设计
好,咱们正式开始动手了。这一章我会带你从零搭建Spring Boot项目,顺便把MySQL装好、配好,再把OA系统的核心表结构设计出来。最后,用JPA逆向生成实体类——这一步能省不少体力活。
我个人习惯是先搭好项目骨架,再设计数据库。为什么呢?因为Spring Boot项目本身不依赖数据库也能跑,先确认项目没问题,再回头搞数据库,排查问题会清晰很多。
2.1 Spring Boot项目搭建
我用的是Spring Initializr,说白了就是start.spring.io这个网站。你打开它,选好Java版本、Spring Boot版本,然后勾上几个依赖就行。
我建议你选这些依赖:
- Spring Web —— 做REST API必备
- Spring Data JPA —— 操作数据库的利器
- MySQL Driver —— 连MySQL用的
- Lombok —— 少写getter/setter,代码清爽
生成后下载下来,用IDEA打开。嗯,这里要注意:如果你用的是IDEA社区版,记得装Lombok插件,不然会报错。
核心配置:application.yml
我个人习惯用yml格式,比properties更直观。下面是我常用的配置模板:
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/oa_system?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf-8
username: root
password: your_password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
format_sql: true
dialect: org.hibernate.dialect.MySQL8Dialect
这里有个坑,我曾经遇到过:ddl-auto: update 在开发阶段很方便,但生产环境千万别用。它会自动改表结构,万一误操作,数据就没了。生产环境建议用 validate 或者手动管理。
2.2 MySQL安装与配置
MySQL的安装我就不一步步截图了,网上教程一大堆。我只说几个关键点:
- 版本选择:我建议用MySQL 8.0+,性能更好,支持窗口函数
- 字符集:建库时一定要用
utf8mb4,别问为什么,你想想看,万一用户名字里带个emoji,用utf8就存不进去了 - 时区:设置成
Asia/Shanghai,不然时间差8小时,排查起来很头疼
建库语句很简单:
CREATE DATABASE oa_system
DEFAULT CHARACTER SET utf8mb4
DEFAULT COLLATE utf8mb4_unicode_ci;
小技巧:我习惯在MySQL的my.cnf里加上 sql_mode=STRICT_TRANS_TABLES,这样插入非法数据时会直接报错,而不是静默截断。调试阶段能省不少事。
2.3 OA系统数据库表结构设计
好,重头戏来了。OA系统的核心是权限管理,说白了就是「谁、能干什么、在哪个部门」。所以我们需要四张核心表:
- 用户表(sys_user) —— 存登录账号、密码、基本信息
- 部门表(sys_dept) —— 存组织架构
- 角色表(sys_role) —— 存角色定义,比如管理员、普通员工
- 权限表(sys_permission) —— 存具体的操作权限,比如「新增用户」、「删除公告」
再加上关联表:用户-角色、角色-权限。这样设计灵活,也符合RBAC(基于角色的访问控制)模型。
下面是我设计的表结构:
2.3.1 用户表(sys_user)
CREATE TABLE sys_user (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(100) NOT NULL,
real_name VARCHAR(50),
email VARCHAR(100),
phone VARCHAR(20),
dept_id BIGINT,
status TINYINT DEFAULT 1 COMMENT '1:启用 0:禁用',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
这里我特意加了 dept_id 字段,直接关联部门表。为什么不做成关联表?因为用户和部门是「多对一」关系,一个用户只能属于一个部门,直接加外键字段更简单。
2.3.2 部门表(sys_dept)
CREATE TABLE sys_dept (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
parent_id BIGINT DEFAULT 0,
sort_order INT DEFAULT 0,
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);
部门表用了 parent_id 实现树形结构。嗯,这里要注意:如果部门层级很深,递归查询会慢。我建议最多支持3级,再深就用缓存或者冗余路径字段。
2.3.3 角色表(sys_role)
CREATE TABLE sys_role (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
code VARCHAR(50) NOT NULL UNIQUE,
description VARCHAR(200),
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);
code 字段是角色的唯一标识,比如 ROLE_ADMIN、ROLE_USER。我建议用这个字段做权限判断,而不是用id,因为id在数据库迁移时可能会变。
2.3.4 权限表(sys_permission)
CREATE TABLE sys_permission (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
permission VARCHAR(100) NOT NULL UNIQUE,
type TINYINT COMMENT '1:菜单 2:按钮 3:API',
parent_id BIGINT DEFAULT 0,
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);
permission 字段是权限标识,比如 user:create、user:delete。我习惯用冒号分隔资源+操作,这样一看就懂。
2.3.5 关联表
CREATE TABLE sys_user_role (
user_id BIGINT NOT NULL,
role_id BIGINT NOT NULL,
PRIMARY KEY (user_id, role_id)
);
CREATE TABLE sys_role_permission (
role_id BIGINT NOT NULL,
permission_id BIGINT NOT NULL,
PRIMARY KEY (role_id, permission_id)
);
避坑指南:我曾经在项目里把关联表的主键设成自增id,结果查询时多了一次索引查找。后来改成联合主键,性能提升明显。记住:关联表不需要自增id,直接用两个外键做联合主键就行。
2.4 JPA逆向生成实体类
表建好了,接下来用JPA自动生成实体类。Spring Data JPA支持从数据库表逆向生成,但说实话,IDEA自带的逆向工具更好用。
操作步骤很简单:
- 在IDEA中打开 Persistence 面板(View → Tool Windows → Persistence)
- 右键项目 → Generate Persistence Mapping → By Database Schema
- 选择数据源,勾选要生成的表
- 设置包名,比如
com.oa.entity - 点击OK,实体类就自动生成了
生成后,你会看到类似这样的代码:
@Entity
@Table(name = "sys_user")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SysUser {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String username;
@Column(nullable = false)
private String password;
@Column(name = "real_name")
private String realName;
private String email;
private String phone;
@ManyToOne
@JoinColumn(name = "dept_id")
private SysDept dept;
private Integer status;
@Column(name = "create_time")
private LocalDateTime createTime;
@Column(name = "update_time")
private LocalDateTime updateTime;
}
注意看,dept_id 字段被自动映射成了 @ManyToOne 关联。这就是JPA的便利之处——你不需要手动写关联查询,直接通过对象导航就能拿到部门信息。
个人经验:逆向生成后,我建议手动检查一下关联关系。比如 @ManyToOne 默认是懒加载(LAZY),但如果你在事务外访问关联对象,会报LazyInitializationException。我一般会在需要的地方加 @Transactional,或者改成 FetchType.EAGER——不过要小心性能问题。
另外,记得给实体类加上 @Data(Lombok的注解),这样getter、setter、toString、equals、hashCode全都有了。代码量直接减半。
好,到这一步,后端项目骨架搭好了,数据库表也设计好了,实体类也生成了。下一章我们会开始写具体的业务逻辑——用户登录、权限校验这些。你想想看,有了这些基础,后面是不是就顺理成章了?