这套极其经典的依赖组合(Spring Boot + MyBatis-Plus + Druid + Lombok + Fastjson),实现一个最短、最少代码、但架构合理、层次分明的 MVP(最小可行性产品),我们可以遵循 Spring Boot 的经典三层架构来进行切分。
为了保证“合理分开代码”的同时做到“最短最少”,我们不写任何一行多余的业务逻辑,仅以一个最核心的“员工管理(Employee)”为例。
1. 怎么切分代码(最合理的最小项目结构)
在 src/main/java/com/example 下建立以下 5 个核心包,职责绝不交叉:
com.example│─ App.java (启动类:项目入口)├─ entity (实体层:对应数据库表,纯数据结构)│ └─ Employee.java├─ mapper (数据访问层:MyBatis-Plus 的核心,负责 SQL)│ └─ EmployeeMapper.java├─ service (业务逻辑层:处理核心业务,这里用 MP 的通用 Service)│ ├─ EmployeeService.java│ └─ impl/EmployeeServiceImpl.java└─ controller (控制层:暴露 HTTP 接口,接收请求、返回 Fastjson 结果)└─ EmployeeController.java
2. 最短、最少的代码实现
1. 实体层 (Entity)
利用 Lombok 消除所有 Getter/Setter,利用 MyBatis-Plus 消除所有 CRUD 的 SQL 映射。
package com.example.entity;import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data;@Data @TableName("employee") // 映射数据库表 public class Employee {@TableId // 主键private Long id;private String username;private String password;private String name;private Integer status; }
2. 数据访问层 (Mapper)
继承 MyBatis-Plus 的 BaseMapper。不需要写任何代码和 XML,就已经自动拥有了增删改查、分页的能力。
package com.example.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.example.entity.Employee; import org.apache.ibatis.annotations.Mapper;@Mapper public interface EmployeeMapper extends BaseMapper<Employee> {// 零代码,自动继承所有单表增删改查方法 }
3. 业务逻辑层 (Service)
利用 MyBatis-Plus 的通用 Service 接口和实现类,同样可以用零行具体代码实现全套业务组合。
-
接口 (Service):
package com.example.service;import com.baomidou.mybatisplus.extension.service.IService; import com.example.entity.Employee;public interface EmployeeService extends IService<Employee> { }
-
实现类 (ServiceImpl):
package com.example.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.entity.Employee; import com.example.mapper.EmployeeMapper; import com.example.service.EmployeeService; import org.springframework.stereotype.Service;@Service public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService {// 零代码,自动获得 MP 强大的批量操作和高级业务方法 }
4. 控制层 (Controller)
这里利用了 Fastjson 进行数据的序列化/反序列化(在请求体中自动解析,并在返回时转换为 JSON)。同时可以用 commons-lang (StringUtils) 来做一行极简的参数校验。
package com.example.controller;import com.alibaba.fastjson.JSON; import com.example.entity.Employee; import com.example.service.EmployeeService; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*;@RestController @RequestMapping("/employee") public class EmployeeController {@Autowiredprivate EmployeeService employeeService;// 1. 新增员工(使用 Fastjson 接收和打印) @PostMappingpublic String save(@RequestBody String jsonStr) {// 使用 Fastjson 解析前端传来的复杂 JSONEmployee employee = JSON.parseObject(jsonStr, Employee.class);// 使用 commons-lang 极简校验if (StringUtils.isBlank(employee.getUsername())) {return "用户名不能为空";}employeeService.save(employee);return "新增成功";}// 2. 根据ID查询员工@GetMapping("/{id}")public String getById(@PathVariable Long id) {Employee employee = employeeService.getById(id);// 使用 Fastjson 将对象序列化为标准 JSON 字符串返回return JSON.toJSONString(employee);} }
5. 启动类 (App)
package com.example;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication public class App {public static void main(String[] args) {SpringApplication.run(App.class, args);} }
3. 配置文件怎么写最少?(application.yml)
在这里把 mysql-connector-java 和 druid-spring-boot-starter 连接池融为一体:
spring:datasource:druid: # 声明使用 Druid 连接池url: jdbc:mysql://localhost:3306/takeout?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8username: rootpassword: yourpassworddriver-class-name: com.mysql.cj.jdbc.Driver
💡 为什么说这是最合理、最少代码的 MVP?
-
依赖分工明确:
-
spring-boot-starter-web负责暴露 HTTP 路由。 -
lombok删掉了几十行的 Getter/Setter 和构造函数。 -
mybatis-plus彻底消灭了 Mapper.xml 和 Service 里的样板 CRUD 代码。 -
druid+mysql-connector默默在底层管理数据库连接。 -
fastjson和commons-lang在 Controller 层协同完成了最快速的“数据解析 + 字符串校验”。
-
-
结构严格分离: 没有任何一层跨职能工作。Controller 只管接发信号,Service 只管业务,Mapper 只管数据。虽然总代码量加起来不过几十行,但它完全具备了向大型企业级项目扩容的骨架。
1. 每一层的数据交互流程(请求的“奇幻旅险”)
当用户在手机上点击一个按钮(比如“点外卖”或“登录”),数据在这一套分层架构中是像接力赛一样流转的。
我们以“大堂经理(后台)新增一个菜品”为例,看看数据(Data)是如何在各层之间传递和演变的:
📱 前端 (浏览器/微信小程序) │ ▼ 【1. 发出 JSON 数据】: {"name":"宫保鸡丁", "price":25.0, "categoryId":1}──Controller 层 (控制层)───────────────────────────────────────────────│ 职责:迎宾、安检、传话。│ 1. 收到 JSON 字符串。│ 2. 用 Fastjson 把 JSON 翻译成 Java 的 Dish 对象。│ 3. 用 commons-lang 检查菜名是不是空的。▼ 【2. 传递 Dish 对象】──Service 层 (业务逻辑层)─────────────────────────────────────────────│ 职责:核心业务逻辑、出谋划策。│ 1. 触发“06-自动填充”:偷偷帮这个菜加上创建时间、创建人。│ 2. 检查这个分类下菜品有没有超过上限(如果有这种业务的话)。▼ 【3. 传递带有完整属性的 Dish 对象】──Mapper 层 (数据访问层)──────────────────────────────────────────────│ 职责:翻译官、数据库打交道。│ 1. MyBatis-Plus 把 Dish 对象自动翻译成 SQL 语句:│ "INSERT INTO dish (name, price) VALUES ('宫保鸡丁', 25.0);"▼ 【4. 发送 SQL 指令】(通过 Druid 连接池和 MySQL 驱动发给数据库)💾 MySQL 数据库 ─── 成功写入一行数据!
2. 图片上的功能,应该分别放在哪一层?
我们把你在前几张图里看到的 16个基础功能 和 9个进阶功能,按照业界最标准的规范进行“对号入座”:
🟢 Controller 层(控制层):负责接口的暴露和接入
只要是直接面对前端、处理 HTTP 请求、管卡口、管输入输出的功能,都写在这里。
-
02-后台功能 / 03-完善登录:接收账号密码,校验成功后发放或验证 JWT 令牌。
-
04/10/12-分页查询:接收前端传来的
page(第几页)和pageSize(每页几条)参数。 -
08-上传&下载:接收前端传过来的
MultipartFile文件,并调用云存储将其变成一个图片 URL。 -
13-短信&验证码:接收手机号,调用短信网关发送,并将验证码存入 Redis。
🔵 Service 层(业务逻辑层):负责核心“商业大脑”
只要涉及到多张表的操作、业务规则校验、状态改变、缓存利用,一律是 Service 层的核心职责。
-
03-新增员工 / 07-新增分类 / 09-新增菜品 / 11-新增套餐:检查数据是否合法,并在写入前做业务处理。
-
05-启用&禁用账号:去数据库查出这个员工,把状态改为 0(禁用)或 1(启用),然后再保存。
-
15-购物车 / 16-用户下单:
-
下单是全项目最复杂的业务:要先查地址簿(14),再查购物车(15),然后算总价,接着往
订单表插入一条,往订单明细表插入多条,最后把购物车清空。这种多表联动、成败在此一举的逻辑,必须写在 Service 层,并加上@Transactional(事务标签)。
-
-
进阶 01/02/03-缓存功能:使用
@Cacheable(Spring Cache)标签。当用户查菜品列表(14)时,Service 优先去 Redis(缓存)里抓取,抓不到才去翻数据库。
🟡 Mapper 层(数据访问层)+ 实体层:纯粹的数据库映射
因为用了 MyBatis-Plus,这一层代码极少,但它在背后默默支撑所有底层的数据库变动。
-
06-自动填充:通过编写一个 MyBatis-Plus 的
MetaObjectHandler配置类。它在 Mapper 层执行insert或update的瞬间触发,自动给实体的createTime等字段塞入当前时间。 -
进阶 04/05-MySQL主从复制与读写分离:通过配置多数据源(比如
Dynamic DataSource)。当 Mapper 执行select开头的语句时,自动把请求引向“从库”;执行insert/update时,引向“主库”。
🟤 项目外部/运维层:不写在 Java 代码里
-
进阶 06/07-Nginx命令与应用:独立安装在 Linux 服务器上的软件,负责把前端静态网页展示给用户,并把后端的
/api请求转发给你的 Spring Boot 项目。 -
进阶 08-前后端分离开发:前端写前端的 Vue/微信小程序,后端写后端的 Java,双方通过 Swagger 接口文档和 JSON 数据进行对接。
-
进阶 09-项目部署:把写好的代码用
maven-plugin打包成jar包,丢到 Linux 服务器上运行。
是的,这里无处不在地用到了控制反转(IoC)和依赖注入(DI)!可以说,如果没有这两个核心概念,上面的代码根本跑不起来。
简单来说:
-
控制反转(IoC - Inversion of Control): 以前我们要用一个对象,得自己
new。现在我们不自己new了,把创建对象的“控制权”翻转交给 Spring 容器(大管家)。大管家启动时,会自动把这些对象创建好,放在一个“大篮子”里。 -
依赖注入(DI - Dependency Injection): 当 A 对象需要用到 B 对象时,不用自己去满世界找,大管家会自动把 B 对象“塞进”(注入) A 对象里面。
那些带着 @ 符号的统称为注解(Annotation),它们就是你给 Spring 大管家下的“秘密指令”。每一个 @ 都有独特的魔法:
1. 告诉大管家:“把这个类实例化,放进你的大篮子里”
为了让 Spring 帮你管理对象,你必须在类名上加以下注解,大管家看到后就会自动 new 它:
-
@SpringBootApplication(在App.java上)-
大白话:这是项目的总指挥官。它告诉 Spring:“我是整个项目的入口,请从我所在的这个包开始,满世界去搜寻带有
@RestController、@Service、@Mapper的类,把它们通通new出来管理起来!”
-
-
@RestController(在EmployeeController上)-
大白话:告诉大管家:“我是一个前台接待员(控制器)。请帮我
new出来,并且帮我连上网络。只要有前端的 HTTP 请求过来,就交给我来处理。另外,我嘴里吐出来的话(返回值),一律自动用 Fastjson 转换成 JSON 字符串发给前端。”
-
-
@Service(在EmployeeServiceImpl上)-
大白话:告诉大管家:“我是一个后厨厨师长(业务逻辑核心)。请帮我
new出来放到篮子里,等会儿前台接待员(Controller)要点菜时会用到我。”
-
-
@Mapper(在EmployeeMapper上)-
大白话:告诉大管家:“我是一个账本抄写员(数据访问层)。虽然我只是个接口,连大括号
{}都没有,但因为我继承了 MyBatis-Plus,请用魔法(动态代理)帮我生成一个实现类,并放进篮子里。等后厨需要查数据库时来找我。”
-
2. 告诉大管家:“我需要那个对象,请把它注入给我”
-
@Autowired(在 Controller 里面调用 Service 时)-
大白话:这就是依赖注入(DI)的施法现场!
-
在
EmployeeController里面,我们写了这一行:Java@Autowired private EmployeeService employeeService;这里我们没有写
= new EmployeeServiceImpl()。Controller 只要往大管家面前一站,头上顶着@Autowired,大管家就会心领神会,立刻去自己的“大篮子”里把刚刚new好的@Service(厨师长)给塞到这个变量里。这就是依赖注入。
-
3. 路由与传参指令(前台接待处的精细分工)
-
@RequestMapping("/employee")-
大白话:划分地盘。告诉大管家:“只要是访问
http://.../employee这个网址的请求,统统带路到我这个类来。”
-
-
@PostMapping/@GetMapping-
大白话:精准对接动作。如果是新增数据(POST 动作),就由
@PostMapping的方法接待;如果是查询数据(GET 动作),就由@GetMapping的方法接待。
-
-
@RequestBody-
大白话:拆包裹。前端发过来的数据是打包在 HTTP 请求体(Body)里的 JSON 字符串。大管家看到这个注解,就会启动 Fastjson,把这堆字符串“拆包”并翻译成 Java 认识的对象或纯字符串。
-
-
@PathVariable-
大白话:顺手牵羊。如果网址写的是
/employee/123,加了@PathVariable Long id,大管家就会自动把网址最后那个123抠出来,赋值给你的id变量。
-
4. 其他小工具指令
-
@Data(Lombok 提供,在实体类上)-
大白话:偷懒神器。写代码时虽然看不见,但编译成 class 文件时,Lombok 看到它就会自动帮这个类生成全套的
Getter/Setter/toString。
-
-
@TableName("employee")(MyBatis-Plus 提供)-
大白话:对暗号。告诉 MyBatis-Plus:“这个 Java 类对应的数据库表名叫
employee,等会儿你自动生成 SQL 语句的时候别写错了。”
-
总结数据流转中的 IoC 与 DI 关系:
-
项目启动(
@SpringBootApplication) ➔ -
大管家自动
new了 Mapper、Service、Controller(IoC 控制反转) ➔ -
大管家发现 Controller 缺了 Service,于是用
@Autowired把 Service 塞了进去(DI 依赖注入) ➔ -
顾客发送请求 ➔ Controller 拿着被注入进来的 Service 顺畅地调用业务逻辑。