一、整体架构图(三层架构)
bash
┌─────────────────────────────────────────────────────┐
│ 前端 (Vue/React) │ 用户界面
│ http://localhost:5173/employee/list │
└──────────────────┬──────────────────────────────────┘
│ HTTP请求
↓
┌─────────────────────────────────────────────────────┐
│ Controller 层(控制器) │ 接收请求
│ @RestController │
│ EmployeeInfoController.java │ ← 在 hrone-admin 模块
│ - 接收HTTP请求 │
│ - 参数验证 │
│ - 调用Service │
└──────────────────┬──────────────────────────────────┘
│ 调用业务方法
↓
┌─────────────────────────────────────────────────────┐
│ Service 层(业务逻辑) │ 处理业务
│ @Service │
│ EmployeeInfoServiceImpl.java │ ← 在 hrone-employeeManagement 模块
│ - 业务逻辑处理 │
│ - 默认值设置 ⭐ │
│ - 数据转换 │
│ - 调用Mapper │
└──────────────────┬──────────────────────────────────┘
│ 调用数据访问方法
↓
┌─────────────────────────────────────────────────────┐
│ Mapper 层(数据访问) │ 访问数据库
│ @Mapper │
│ EmployeeInfoMapper.java (接口) │ ← 在 hrone-employeeManagement 模块
│ EmployeeInfoMapper.xml (SQL实现) │
│ - 定义SQL语句 │
│ - 执行数据库操作 │
└──────────────────┬──────────────────────────────────┘
│ SQL查询
↓
┌─────────────────────────────────────────────────────┐
│ 数据库 (MySQL) │ 存储数据
│ tb_employee_info 表 │
└─────────────────────────────────────────────────────┘
二、一次完整请求的生命周期
让我用查询员 工列 表的实际例子来说明:
第1步:用户操作
bash
// 用户在浏览器打开员工管理页面
// 前端发送请求
GET http://localhost:8085/base/employeeInfo/list?pageNum=1&pageSize=10
第2步:Controller 接收请求
java
//EmployeeInfoController.java
@RestController
@RequestMapping("/employeeInfo")
public class EmployeeInfoController extends BaseController {
@Autowired
private IEmployeeInfoService EmployeeInfoService; // ← 注入Service
@GetMapping("/list") // ← 这个方法接收 GET /employeeInfo/list 请求
public TableDataInfo list(@RequestParam MultiValueMap<String, String> allRequestParams) {
// 1. 接收到参数:pageNum=1, pageSize=10
System.out.println("收到请求参数: " + allRequestParams);
// 2. 调用Service层处理业务
List<Map<String, ?>> list = EmployeeInfoService.selectEmployeeInfoByAttributes(allRequestParams);
// ↑ 调用Service层的方法
// 3. 封装结果返回给前端
return getDataTable(list);
}
}
作用:
- 🎯 负责接收HTTP请求
- 📦 提取请求参数
- 🔗 调用Service层的业务方法
- 📤 返回JSON响应给前端
第3步:Service 处理业务逻辑
java
//EmployeeInfoServiceImpl.java
@Service
public class EmployeeInfoServiceImpl implements IEmployeeInfoService {
@Autowired
private EmployeeInfoMapper employeeInfoMapper; // ← 注入Mapper
@Override
public List<Map<String, ?>> selectEmployeeInfoByAttributes(MultiValueMap<String, String> allRequestParams) {
// 1️⃣ 业务逻辑:设置默认值(您刚修改的部分)
LinkedMultiValueMap<String, Object> equalsMap = new LinkedMultiValueMap<>();
// 如果用户没有指定 employee_active,默认只查询在职员工
if (!allRequestParams.containsKey("employee_active")) {
equalsMap.add("employee_active", true); // ← 默认值逻辑
}
// 2️⃣ 业务逻辑:参数解析、类型转换等
// ... 省略中间代码 ...
// 3️⃣ 调用Mapper层执行SQL查询
return employeeInfoMapper.searchEmployeeAttributes(systemColumnIds, clientAttributeTypes, likeMap, equalsMap);
// ↑ 调用Mapper接口的方法
}
}
作用:
- 🧠 处理业务逻辑(如设置默认值)
- 🔄 数据转换和验证
- 🗄️ 调用Mapper执行数据库操作
第4步:Mapper 执行SQL
4.1 Mapper 接口(定义方法)
java
//EmployeeInfoMapper.java
@Mapper
public interface EmployeeInfoMapper {
// 定义方法签名,但不写实现
List<Map<String, Object>> searchEmployeeAttributes(
@Param("systemColIds") List<String> systemColIds,
@Param("clientAttributeTypes") Map<String, String> clientAttributeTypes,
@Param("likeMap") MultiValueMap<String, String> likeMap,
@Param("equalsMap") MultiValueMap<String, Object> equalsMap
);
// ↑ 这只是接口定义,真正的SQL在XML文件中
}
4.2 Mapper XML(SQL实现)
XML
//EmployeeInfoMapper.xml
<mapper namespace="com.hrone.base.employeeManagement.mapper.EmployeeInfoMapper">
<!-- 这个id对应Java接口中的方法名 -->
<select id="searchEmployeeAttributes" resultType="hashmap">
SELECT * FROM (
SELECT employee_id, employee_name, employee_active, ...
FROM tb_employee_info
) AS parsed
<where>
<!-- 处理equalsMap中的条件 -->
<if test="equalsMap != null and equalsMap.size() > 0">
<foreach collection="equalsMap" item="valuelist" index="key">
`${key}` IN
<foreach collection="valuelist" item="value" open="(" close=")" separator=",">
#{value}
</foreach>
</foreach>
</if>
</where>
</select>
</mapper>
这一步生成的SQL:
sql
SELECT * FROM (
SELECT employee_id, employee_name, employee_active, ...
FROM tb_employee_info
) AS parsed
WHERE employee_active IN (1) -- ← 这个1就是Service层设置的true
作用:
- 📝 定义具体的SQL语句
- 🔀 动态拼接WHERE条件
- 🗃️ 执行数据库查询
第5步:数据库返回结果
bash
MySQL数据库执行SQL → 返回数据 → Mapper → Service → Controller → 前端
三、模块之间的关系
bash
┌─────────────────────────────────────────────┐
│ hrone-base-server (父项目) │
│ pom.xml │ ← 管理所有子模块
└─────────────────────┬───────────────────────┘
│
┌───────────┴───────────┬─────────────┐
│ │ │
┌─────────▼─────────┐ ┌─────────▼─────────┐ ┌▼─────────────┐
│ hrone-admin │ │ hrone-employee │ │ hrone-common │
│ (主应用模块) │ │ Management │ │ (公共工具) │
│ │ │ (员工管理模块) │ │ │
│ ✅ Controller │ │ │ │ ✅ 工具类 │
│ ✅ 启动类 │ │ ✅ Service │ │ ✅ 基础类 │
│ ✅ 配置文件 │ │ ✅ Mapper │ │ ✅ 注解 │
│ │ │ ✅ Domain │ │ │
└─────────┬─────────┘ └─────────┬─────────┘ └──────────────┘
│ │
│ 依赖关系 (pom.xml) │
│ <dependency> │
└──────────►────────────┘
依赖关系说明:
java
<!-- hrone-admin 的 pom.xml -->
<dependencies>
<!-- 依赖员工管理模块 -->
<dependency>
<groupId>com.hrone</groupId>
<artifactId>hrone-employeeManagement</artifactId>
</dependency>
<!-- 依赖公共模块 -->
<dependency>
<groupId>com.hrone</groupId>
<artifactId>hrone-common</artifactId>
</dependency>
</dependencies>
意思是:
- hrone-admin 可以使用 hrone-employeeManagement 中的所有类
- Controller 在 hrone-admin,Service/Mapper 在 hrone-employeeManagement
- 通过 @Autowired 就能互相调用
四、代码调用链路(实际例子)
以您修改的代码为例:
java
// 1️⃣ 前端请求
GET /employeeInfo/list
↓
// 2️⃣ Controller接收(hrone-admin模块)
@GetMapping("/list")
public TableDataInfo list(@RequestParam MultiValueMap<String, String> allRequestParams) {
List<Map<String, ?>> list = EmployeeInfoService.selectEmployeeInfoByAttributes(allRequestParams);
return getDataTable(list);
}
↓
// 3️⃣ Service处理(hrone-employeeManagement模块)
public List<Map<String, ?>> selectEmployeeInfoByAttributes(MultiValueMap<String, String> allRequestParams) {
// ⭐ 您修改的代码在这里
if (!allRequestParams.containsKey("employee_active")) {
equalsMap.add("employee_active", true); // 默认只查在职员工
}
// 调用Mapper
return employeeInfoMapper.searchEmployeeAttributes(...);
}
↓
// 4️⃣ Mapper接口(hrone-employeeManagement模块)
List<Map<String, Object>> searchEmployeeAttributes(...);
↓
// 5️⃣ Mapper XML(hrone-employeeManagement/resources/mapper)
<select id="searchEmployeeAttributes">
SELECT * FROM tb_employee_info
WHERE employee_active = #{value} ← 这里的value就是true
</select>
↓
// 6️⃣ MySQL数据库
执行SQL: SELECT * FROM tb_employee_info WHERE employee_active = 1
↓
// 7️⃣ 返回数据
数据库 → Mapper → Service → Controller → 前端
五、关键概念对比
|-------------------|-------|---|-----------|---------------|
| 层级 | 文件类型 | | 作用 | 类比 |
| Controller | .java | | 接收请求、返回响应 | 餐厅的服务员(接单、上菜) |
| Service | .java | | 业务逻辑处理 | 餐厅的经理(决定怎么做) |
| Mapper接 口 | .java | | 定义数据操作方法 | 菜单(列出有什么菜) |
| Mapper XML | .xml | | SQL语句实现 | 菜谱(具体怎么做菜) |
| Domain | .java | | 数据实体类 | 菜品(数据的样子) |
| Database | MySQL | | 存储数据 | 食材仓库(存放原材料) |
六、为什么要分这么多层?
1. 职责分离
java
Controller → 只管接收请求和返回响应(不管业务逻辑)
Service → 只管业务逻辑(不管HTTP请求)
Mapper → 只管数据库操作(不管业务)
2. 代码复用
// Service可以被多个Controller调用
EmployeeInfoController → EmployeeInfoService
AttendanceController → EmployeeInfoService // 考勤也需要员工信息
3. 易于测试和维护
// 单独测试业务逻辑,不需要启动整个服务器
@Test
public void testService() {
EmployeeInfoService service = new EmployeeInfoServiceImpl();
// 测试业务逻辑
}
七、总结:记住这个流程就够了
用户点击按钮
↓
前端发送HTTP请求
↓
Controller 接收请求(入口)
↓
Service 处理业务逻辑(您修改的地方 ⭐)
↓
Mapper 执行SQL语句
↓
Database 返回数据
↓
原路返回到前端