1. 项目概述
今天我们要完成一个基于SpringBoot的部门管理系统开发,实现部门数据的增删查改功能。这是一个典型的Java Web应用开发案例,涉及前后端分离架构、RESTful API设计、MyBatis数据库操作等核心技术点。
这个系统主要包含两大功能模块:
- 部门管理:部门列表查询、新增部门、修改部门、删除部门
- 员工管理:员工列表查询(分页+条件)、新增员工、修改员工、删除员工
作为Java学习第14天的实战项目,我们将从零开始搭建整个后端系统,并与已准备好的前端工程进行联调测试。通过这个案例,你将掌握:
- SpringBoot项目的基本结构搭建
- MyBatis与MySQL的集成使用
- RESTful API的设计规范
- 前后端分离开发模式的实际应用
- 日志记录与异常处理的最佳实践
2. 环境准备与项目搭建
2.1 技术栈选型
后端技术栈:
- Spring Boot 2.7.x
- MyBatis
- MySQL 8.0
- Lombok
- Logback
前端技术栈:
- Vue.js
- Element UI
- Axios
开发工具:
- IntelliJ IDEA
- Postman
- Navicat/MySQL Workbench
2.2 数据库设计
我们首先需要准备两张基础表:
部门表(dept)
sql复制CREATE TABLE `dept` (
`id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',
`name` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '部门名称',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_time` datetime NOT NULL COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
员工表(emp)
sql复制CREATE TABLE `emp` (
`id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',
`username` varchar(20) COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名',
`password` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '密码',
`name` varchar(10) COLLATE utf8mb4_general_ci NOT NULL COMMENT '姓名',
`gender` tinyint NOT NULL COMMENT '性别, 1:男, 2:女',
`image` varchar(300) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '图像url',
`job` tinyint DEFAULT NULL COMMENT '职位, 1:班主任, 2:讲师, 3:学工主管, 4:教研主管',
`entrydate` date DEFAULT NULL COMMENT '入职日期',
`dept_id` int DEFAULT NULL COMMENT '部门ID',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_time` datetime NOT NULL COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`),
KEY `dept_id` (`dept_id`),
CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`dept_id`) REFERENCES `dept` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
2.3 SpringBoot工程初始化
使用Spring Initializr创建项目时,需要选择以下依赖:
- Spring Web
- MyBatis Framework
- MySQL Driver
- Lombok
项目结构如下:
code复制src/
├── main/
│ ├── java/
│ │ └── com/
│ │ └── example/
│ │ ├── TliasApplication.java
│ │ ├── controller/
│ │ ├── pojo/
│ │ ├── service/
│ │ │ ├── impl/
│ │ └── mapper/
│ └── resources/
│ ├── application.properties
│ └── static/
└── test/
2.4 配置文件设置
在application.properties中配置数据库连接和MyBatis:
properties复制# 数据库配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/tlias?useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
# MyBatis配置
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
3. 部门管理功能实现
3.1 查询部门列表
3.1.1 接口设计
请求方式:GET
请求路径:/depts
请求参数:无
响应数据:
json复制{
"code": 1,
"msg": "success",
"data": [
{
"id": 1,
"name": "学工部",
"createTime": "2022-09-01T23:06:29",
"updateTime": "2022-09-01T23:06:29"
},
{
"id": 2,
"name": "教研部",
"createTime": "2022-09-01T23:06:29",
"updateTime": "2022-09-01T23:06:29"
}
]
}
3.1.2 代码实现
实体类(Dept.java)
java复制@Data
@NoArgsConstructor
@AllArgsConstructor
public class Dept {
private Integer id;
private String name;
private LocalDateTime createTime;
private LocalDateTime updateTime;
}
Mapper接口(DeptMapper.java)
java复制@Mapper
public interface DeptMapper {
@Select("select id, name, create_time, update_time from dept")
List<Dept> list();
}
Service层(DeptService.java)
java复制public interface DeptService {
List<Dept> list();
}
ServiceImpl(DeptServiceImpl.java)
java复制@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptMapper deptMapper;
@Override
public List<Dept> list() {
return deptMapper.list();
}
}
Controller层(DeptController.java)
java复制@Slf4j
@RestController
@RequestMapping("/depts")
public class DeptController {
@Autowired
private DeptService deptService;
@GetMapping
public Result list() {
log.info("查询所有部门数据");
List<Dept> deptList = deptService.list();
return Result.success(deptList);
}
}
3.1.3 统一响应封装
java复制@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
private Integer code;
private String msg;
private Object data;
public static Result success() {
return new Result(1, "success", null);
}
public static Result success(Object data) {
return new Result(1, "success", data);
}
public static Result error(String msg) {
return new Result(0, msg, null);
}
}
3.2 删除部门
3.2.1 接口设计
请求方式:DELETE
请求路径:/depts/{id}
请求参数:路径参数id
响应数据:
json复制{
"code":1,
"msg":"success",
"data":null
}
3.2.2 代码实现
Mapper接口
java复制@Delete("delete from dept where id = #{id}")
void deleteById(Integer id);
Service层
java复制void delete(Integer id);
ServiceImpl
java复制@Override
public void delete(Integer id) {
deptMapper.deleteById(id);
}
Controller层
java复制@DeleteMapping("/{id}")
public Result delete(@PathVariable Integer id) {
log.info("根据id删除部门: {}", id);
deptService.delete(id);
return Result.success();
}
3.3 新增部门
3.3.1 接口设计
请求方式:POST
请求路径:/depts
请求参数:
json复制{
"name": "教研部"
}
响应数据:
json复制{
"code":1,
"msg":"success",
"data":null
}
3.3.2 代码实现
Mapper接口
java复制@Insert("insert into dept (name, create_time, update_time) values (#{name},#{createTime},#{updateTime})")
void insert(Dept dept);
Service层
java复制void add(Dept dept);
ServiceImpl
java复制@Override
public void add(Dept dept) {
dept.setCreateTime(LocalDateTime.now());
dept.setUpdateTime(LocalDateTime.now());
deptMapper.insert(dept);
}
Controller层
java复制@PostMapping
public Result add(@RequestBody Dept dept) {
log.info("新增部门:{}", dept);
deptService.add(dept);
return Result.success();
}
3.4 修改部门
3.4.1 接口设计
请求方式:PUT
请求路径:/depts
请求参数:
json复制{
"id": 1,
"name": "教研部"
}
响应数据:
json复制{
"code":1,
"msg":"success",
"data":null
}
3.4.2 代码实现
Mapper接口
java复制@Update("update dept set name=#{name}, update_time=#{updateTime} where id=#{id}")
void update(Dept dept);
Service层
java复制void update(Dept dept);
ServiceImpl
java复制@Override
public void update(Dept dept) {
dept.setUpdateTime(LocalDateTime.now());
deptMapper.update(dept);
}
Controller层
java复制@PutMapping
public Result update(@RequestBody Dept dept) {
log.info("修改部门:{}", dept);
deptService.update(dept);
return Result.success();
}
4. 前后端联调与测试
4.1 前端环境配置
- 将前端工程解压到无中文路径的目录
- 启动Nginx服务器
- 访问http://localhost:90
4.2 接口测试要点
-
查询部门列表:
- 验证返回数据是否完整
- 检查时间格式是否正确
-
新增部门:
- 测试空名称处理
- 测试重复名称处理
- 验证创建时间是否自动填充
-
修改部门:
- 测试不存在的ID处理
- 验证更新时间是否自动更新
-
删除部门:
- 测试删除不存在的ID
- 测试删除有员工的部门(应有外键约束)
4.3 常见问题排查
-
跨域问题:
- 确保后端添加@CrossOrigin注解
- 检查Nginx代理配置是否正确
-
日期格式问题:
- 前端显示不正常时可添加Jackson日期格式化配置
-
参数绑定失败:
- 检查前端传参命名是否与实体类属性一致
- 验证@RequestBody注解是否正确使用
5. 项目优化与扩展
5.1 代码优化建议
-
异常处理:
- 添加全局异常处理器
- 对数据库操作进行try-catch
-
参数校验:
- 使用Hibernate Validator进行参数校验
- 添加非空、长度等基础校验
-
日志优化:
- 添加操作日志记录
- 配置日志级别和输出格式
5.2 功能扩展方向
-
部门树形结构:
- 实现多级部门管理
- 添加父部门ID字段
-
部门统计功能:
- 统计各部门员工数量
- 按时间维度统计部门变化
-
导入导出:
- 实现Excel导入导出功能
- 支持部门数据批量操作
6. 开发经验总结
在实际开发过程中,有几个关键点需要特别注意:
-
RESTful规范:
- 保持URL设计的规范性
- 正确使用HTTP方法
- 统一响应格式
-
MyBatis使用技巧:
- 使用@Param注解明确参数名
- 复杂SQL使用XML配置方式
- 启用驼峰命名自动映射
-
事务管理:
- 对写操作添加@Transactional
- 设置合适的事务隔离级别
-
性能考虑:
- 高频查询添加缓存
- 批量操作使用批量插入
- 合理设计数据库索引
通过这个项目的完整开发流程,我们不仅掌握了基础的CRUD操作,更重要的是理解了企业级应用的标准开发模式和规范。这些经验对于后续更复杂系统的开发具有重要指导意义。