工程搭建
略
项目初始包结构
-
com.tlias
- .TliasWebManagementApplication:启动类
- .controller:Controller控制层代码,负责接收请求、处理参数、响应数据
- .service:Service业务逻辑层代码,负责业务逻辑的处理
- .mapper:数据访问层代码,负责对数据库进行CRUD的操作
- .config:配置代码
- .common:通用代码,例如工具类、全局常量、枚举、异常等
- .dto:数据传递代码,负责在 Controller ↔ Service 或 Service ↔ Service 之间传递数据
- .vo:用于 Controller 返回给前端的最终数据结构
- .po:与数据库表字段严格对应

Controller、Service、Mapper 核心职责
- Controller:作为前端与后端的 "接口人",接收前端请求,协调调用对应 Service,最终返回处理结果。
- Service:专注业务逻辑处理,如数据校验、规则计算等,是核心业务的 "执行者",需时调用 Mapper 操作数据。
- Mapper:仅负责与数据库交互,执行增删改查,是数据存取的 "专属通道",不处理复杂业务。
三者协作流程:前端请求 → Controller → Service → Mapper → 数据库,再逆向返回结果,形成完整数据处理链路。
我们现在来完成基础的查询部门功能
DeptController
java
package com.tlias.tliaswebmanagement.controller;
import com.tlias.tliaswebmanagement.common.Result;
import com.tlias.po.Dept;
import com.tlias.service.DeptService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 部门控制器
*/
@RestController
@RequiredArgsConstructor
public class DeptController {
/**
* 依赖注入部门业务逻辑层对象到当前类中,方便后续使用
* SpringBoot官方不推荐@Autowired注解,而是推荐使用@RequiredArgsConstructor注解
*/
private final DeptService deptService;
/**
* 1. 查询部门列表
* 根据接口文档可知,是GET请求,需要使用@GetMapping注解处理,并补全路径 "/depts"
* 根据接口文档可知,返回的是统一响应结果Result,并且结果封装的是Dept部门对象集合
*/
@GetMapping("/depts")
public Result<List<Dept>> list() {
//1.1 调用部门业务逻辑层,获取部门列表数据
List<Dept> deptList = deptService.list();
//1.2 将部门列表数据,封装到Result统一响应结果对象中返回
return Result.success(deptList);
}
}
DeptService
java
package com.tlias.tliaswebmanagement.service;
import com.tlias.po.Dept;
import java.util.List;
/**
* 部门业务逻辑层
*/
public interface DeptService {
/**
* 查询所有部门
*/
List<Dept> list();
}
DeptServiceImpl
java
package com.tlias.tliaswebmanagement.service.impl;
import com.tlias.po.Dept;
import com.tlias.tliaswebmanagement.mapper.DeptMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 部门业务逻辑层实现类,需要加@Service注解
*/
@Service
public class DeptServiceImpl implements com.tlias.service.DeptService {
@Autowired
private DeptMapper deptMapper;
/**
* 1.查询部门列表
*/
@Override
public List<Dept> list() {
//1.1 由于获取部门列表数据的逻辑及其简单,这里就只需要调用数据访问层对象,让其拿到结果即可
List<Dept> deptList =deptMapper.selectAll();
//1.2 获取到的部门集合返回给Controller控制层
return deptList;
}
}
DeptMapper
java
package com.tlias.tliaswebmanagement.mapper;
import com.tlias.po.Dept;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* 部门映射器
* 对于Mabatis框架,数据访问层代码需要加@Mapper注解
*/
@Mapper
public interface DeptMapper {
/**
* 1.查询tb_dept表,查询所有数据,使用@Select注解
*/
@Select("select * from tb_dept")
List<Dept> selectAll();
}
"依赖注入优化" 主要指的是通过 lombok.RequiredArgsConstructor 注解替代传统的 @Autowired 注解来实现依赖注入,这种方式是 Spring Boot 官方更推荐的做法,核心优势如下:
1. 为什么不推荐 @Autowired?
-
潜在问题 :
@Autowired可以直接标注在字段上实现注入,但这种方式会导致:- 依赖关系不明显,从代码上难以直观看出类依赖了哪些对象(需要翻找注解位置)。
- 可能引发空指针风险(若注入失败,编译期无法发现,运行时才报错)。
- 不利于单元测试(难以手动构造依赖对象进行模拟测试)。
2. @RequiredArgsConstructor 优化在哪里?
-
原理 :这是 Lombok 提供的注解,作用是自动生成包含所有
final修饰的成员变量的构造方法 。Spring 会通过这个构造方法,将依赖的对象(如DeptService、DeptMapper)自动传入并赋值,实现依赖注入。 -
优势:
- 依赖关系更清晰 :被注入的对象必须用
final修饰(如private final DeptService deptService),一眼就能看出类依赖了哪些组件。 - 避免空指针 :
final变量必须初始化,若忘记注入或注入失败,编译期就会报错,提前暴露问题。 - 便于测试:可以通过构造方法手动传入模拟对象(如 Mock 测试),更符合面向对象的设计原则。
- 依赖关系更清晰 :被注入的对象必须用
总结
简单说,@RequiredArgsConstructor 替代 @Autowired 的本质是:用 "构造方法注入" 替代 "字段注入" ,通过强制 final 修饰和自动生成构造方法,让依赖关系更明确、代码更健壮,同时规避了 @Autowired 的潜在风险,这也是 Spring 官方推荐的依赖注入最佳实践。
删除部门功能:
-
DeptController部分代码
kotlin/** * 2. 根据ID删除部门 * 根据接口文档可知,请求是DELETE类型,使用 @DeleteMapping 注解处理,并补全路径 "/depts" */ @DeleteMapping( "/depts" ) public Result delete(Integer id) { //2.1 利用部门业务逻辑层对象deptService,传入id,让其执行删除部门的逻辑代码 deptService.deleteById(id); //2.2 返回一个默认的成功结果 return Result.success(); }-
Service
-
-
思路:利用deptMapper数据访问层对象,根据传入的id删除数据表中的对应部门数据
-
DeptService接口
javapackage com.tlias.service; import com.tlias.po.Dept; import java.util.List; /** * 部门业务逻辑层 */ public interface DeptService { /** * 查询所有部门 */ List<Dept> list(); /** * 根据ID删除部门 */ void deleteById(Integer id); }-
DeptServiceImpl部分代码
typescript/** * 2. 根据ID删除部门 */ @Override public void deleteById(Integer id) { //2.1 利用deptMapper数据访问层对象,根据传入的id删除数据表中的对应部门数据 deptMapper.deleteById(id); } -
Mapper
-
思路
- sql语句:delete from tb_dept where id = 指定的ID值;
- 定义deleteById方法,处理删除功能
- 在方法上使用@Delete注解,放入对应sql语句,需要传入的值,使用#{...}占位符填充
-
DeptMapper部分代码
java/** * 2.根据ID删除部门 * 删除操作,使用 @Delete 注解 */ @Delete( "delete from tb_dept where id = #{id}" ) void deleteById(Integer id);