SpringBoot学习第二天:实现CRUD接口 + 吃透Bean核心原理
SpringBoot学习第二天:实现CRUD接口 + 吃透Bean核心原理
哈喽,各位一起学SpringBoot的小伙伴~ 今天是SpringBoot学习的第二天,昨天我们搭建好了SpringBoot的基础项目,了解了项目的核心结构和启动原理。今天我们重点做两件事:一是上手实现最常用的CRUD接口(增删改查),感受SpringBoot的便捷;二是搞懂Spring核心中的核心——Bean的原理,搞明白“为什么我们写个类,Spring就能自动帮我们管理”。
全程无复杂操作,贴合新手节奏,每一步都有详细说明,跟着做就能搞定,话不多说,开始今天的学习!
一、前期准备(衔接第一天,快速上手)
首先,我们基于第一天搭建的SpringBoot项目,补充必要的依赖(如果第一天没搭好,也可以直接新建一个SpringBoot项目,勾选对应的依赖即可)。
1. 补充pom.xml依赖
我们需要用到SpringMVC(接口开发)、MyBatis-Plus(简化数据库操作)、MySQL驱动(连接数据库)、lombok(简化实体类代码),在pom.xml中添加以下依赖(如果新建项目时已经勾选,可跳过):
<!-- SpringMVC 依赖(SpringBoot自带,无需额外添加,确保有spring-boot-starter-web即可) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis-Plus 依赖(简化CRUD,比原生MyBatis更便捷) -->
<dependency>
<groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- lombok 依赖(简化实体类,无需写get/set/toString) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
2. 配置application.yml(连接数据库)
在resources目录下的application.yml中,添加数据库连接配置(替换成自己的MySQL账号和密码),SpringBoot会自动加载该配置,无需手动配置数据源:
spring:
# 数据库连接配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot_demo?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
username: root # 你的MySQL账号
password: 123456 # 你的MySQL密码
# MyBatis-Plus 配置
mybatis-plus:
mapper-locations: classpath:mapper/**/*.xml # mapper.xml文件路径(如果不用xml,可省略)
type-aliases-package: com.example.springbootdemo.entity # 实体类包路径
configuration:
map-underscore-to-camel-case: true # 开启下划线转驼峰(数据库字段user_name → 实体类userName)
3. 数据库准备
新建一个数据库(springboot_demo),再新建一张user表,用于后续CRUD操作,SQL语句如下(直接在MySQL客户端执行即可):
CREATE DATABASE IF NOT EXISTS springboot_demo;
USE springboot_demo;
CREATE TABLE IF NOT EXISTS user (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
name VARCHAR(50) NOT NULL COMMENT '姓名',
age INT COMMENT '年龄',
email VARCHAR(100) COMMENT '邮箱',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) COMMENT '用户表';
二、实战:实现CRUD接口(核心环节)
我们采用“实体类 → Mapper → Service → Controller”的分层结构(这是SpringBoot项目的标准分层,便于维护),一步步实现增删改查,每一步都极简,新手也能轻松跟上。
1. 实体类(Entity)
在com.example.springbootdemo(替换成你自己的包名)下新建entity包,创建User实体类,使用lombok的@Data注解,简化get/set/toString方法:
package com.example.springbootdemo.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data // lombok注解,自动生成get/set/toString/equals/hashCode方法
@TableName("user") // 关联数据库中的user表
public class User {
@TableId(type = IdType.AUTO) // 主键自增
private Long id;
private String name;
private Integer age;
private String email;
private LocalDateTime createTime;
private LocalDateTime updateTime;
}
2. Mapper接口
新建mapper包,创建UserMapper接口,继承MyBatis-Plus的BaseMapper,BaseMapper已经封装好了CRUD的基础方法,我们无需写任何SQL,直接继承即可使用:
package com.example.springbootdemo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.springbootdemo.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper // 标记该接口是MyBatis的Mapper接口,SpringBoot会自动扫描
public interface UserMapper extends BaseMapper<User> {
// 无需写任何方法,BaseMapper已封装好CRUD(selectById、insert、updateById、deleteById等)
}
3. Service层
新建service包,创建UserService接口和其实现类UserServiceImpl,Service层用于封装业务逻辑(这里我们先简单调用Mapper的方法,后续再扩展复杂业务)。
(1)UserService接口
package com.example.springbootdemo.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.springbootdemo.entity.User;
// 继承IService,IService是MyBatis-Plus提供的服务层接口,封装了更全面的CRUD方法
public interface UserService extends IService<User> {
}
(2)UserServiceImpl实现类
package com.example.springbootdemo.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.springbootdemo.entity.User;
import com.example.springbootdemo.mapper.UserMapper;
import com.example.springbootdemo.service.UserService;
import org.springframework.stereotype.Service;
@Service // 标记该类是Spring的服务层Bean,Spring会自动管理
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
// 无需写任何实现,ServiceImpl已实现IService的所有方法,直接调用即可
}
4. Controller层(接口对外提供)
新建controller包,创建UserController,编写CRUD接口,使用@RestController注解,让接口返回JSON格式数据(适合前后端分离):
package com.example.springbootdemo.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.springbootdemo.entity.User;
import com.example.springbootdemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController // 等价于 @Controller + @ResponseBody,返回JSON数据
@RequestMapping("/user") // 接口统一前缀,所有接口都以 /user 开头
public class UserController {
// 自动注入UserService,Spring会自动创建UserService的实例,无需我们手动new
@Autowired
private UserService userService;
// 1. 新增用户(POST请求)
@PostMapping
public boolean addUser(@RequestBody User user) {
// 调用Service的save方法,新增用户,返回是否成功
return userService.save(user);
}
// 2. 删除用户(DELETE请求,路径传参)
@DeleteMapping("/{id}")
public boolean deleteUser(@PathVariable Long id) {
// 调用Service的removeById方法,根据ID删除用户
return userService.removeById(id);
}
// 3. 更新用户(PUT请求)
@PutMapping
public boolean updateUser(@RequestBody User user) {
// 调用Service的updateById方法,根据ID更新用户
return userService.updateById(user);
}
// 4. 根据ID查询用户(GET请求,路径传参)
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
// 调用Service的getById方法,根据ID查询用户
return userService.getById(id);
}
// 5. 查询所有用户(GET请求)
@GetMapping
public List<User> getAllUser() {
// 调用Service的list方法,查询所有用户
return userService.list();
}
}
5. 启动项目,测试接口
启动SpringBoot的主启动类(SpringBootDemoApplication),启动成功后,我们可以用Postman、浏览器或curl工具测试接口,这里给出简单的测试示例:
-
查询所有用户:GET http://localhost:8080/user
-
根据ID查询:GET http://localhost:8080/user/1
-
新增用户:POST http://localhost:8080/user ,请求体JSON:
-
更新用户:PUT http://localhost:8080/user ,请求体JSON:
-
删除用户:DELETE http://localhost:8080/user/1
测试成功后,就说明我们的CRUD接口已经实现完成了!是不是比SSM框架简单太多?不用配置XML,不用手动管理Bean,SpringBoot帮我们做了所有繁琐的工作。
三、核心解析:SpringBoot中的Bean原理(新手能懂版)
在刚才的代码中,我们用到了@Service、@Mapper、@RestController、@Autowired这些注解,不知道大家有没有疑惑:为什么我们写个类,加个@Service注解,Spring就能自动帮我们创建实例?为什么@Autowired就能直接拿到这个实例?这背后的核心,就是Spring的Bean管理机制。
先给大家一个通俗的比喻:Spring就像一个“容器”(可以理解为一个“工具箱”),Bean就是这个工具箱里的“工具”。我们通过注解告诉Spring:“这个类是个工具,你帮我保管好,我要用的时候直接找你拿”,Spring就会自动创建这个类的实例(Bean),并管理它的生命周期(创建、使用、销毁)。
1. 什么是Bean?
Bean就是Spring容器管理的对象,本质上就是我们写的Java类的实例,但这个实例不是我们手动new的,而是由Spring容器创建、初始化和管理的。比如我们写的UserServiceImpl,加了@Service注解后,Spring就会自动创建一个UserServiceImpl的实例,这个实例就是Bean。
简单说:Bean = Spring容器管理的Java对象,我们不用手动new,直接用@Autowired就能拿到。
2. SpringBoot如何扫描并创建Bean?
SpringBoot的主启动类上有一个@SpringBootApplication注解,这个注解里面包含了一个@ComponentScan注解(核心注解),它的作用是:自动扫描主启动类所在包及其子包下的所有带有特定注解的类,将其创建为Bean。
哪些注解会被扫描?就是我们刚才用到的:
-
@Component:通用注解,标记一个类为Bean(一般用于普通类)
-
@Service:专门用于Service层的Bean(本质是@Component的子类)
-
@Controller:专门用于Controller层的Bean(本质是@Component的子类)
-
@Mapper:MyBatis的注解,SpringBoot会将其扫描为MapperBean(用于数据库操作)
这就是为什么我们的UserServiceImpl加了@Service,Spring就能自动创建它的实例——因为@SpringBootApplication注解的@ComponentScan扫描到了它。
3. @Autowired:自动注入Bean
在UserController中,我们用@Autowired注解注入了UserService,这一步的作用是:让Spring从容器中找到UserService类型的Bean,自动赋值给userService变量,我们不用手动new UserServiceImpl(),就能直接使用它的方法。
举个例子:你把工具(Bean)放进了工具箱(Spring容器),用的时候不用自己找,告诉工具箱“我要这个工具”(@Autowired),工具箱就会自动把工具递给你。
4. Bean的生命周期(简单了解)
Spring管理Bean的整个过程,就像一个人的生命周期:
-
实例化:Spring创建Bean的实例(相当于new UserServiceImpl())
-
初始化:Spring对Bean进行初始化(比如设置属性、调用初始化方法)
-
使用:我们通过@Autowired拿到Bean,调用它的方法(比如userService.save(user))
-
销毁:Spring容器关闭时,销毁Bean(释放资源)
对于新手来说,不用深入研究每一步的细节,只要知道:Spring会全程管理Bean,我们只需要关注业务逻辑即可。
5. 关键总结(必记)
-
@SpringBootApplication:核心注解,包含@ComponentScan,自动扫描Bean
-
@Service/@Controller/@Mapper:标记类为Bean,让Spring扫描并创建
-
@Autowired:从Spring容器中获取Bean,无需手动new
-
Bean:Spring容器管理的对象,是Spring的核心
四、今日总结与明日预告
今日总结
1. 我们实现了SpringBoot的CRUD接口,采用“实体类→Mapper→Service→Controller”分层结构,借助MyBatis-Plus简化了数据库操作,无需写复杂SQL;
2. 搞懂了Bean的核心原理:Spring容器管理Bean,通过注解扫描创建Bean,通过@Autowired注入Bean,不用手动管理对象,这也是SpringBoot“简化开发”的核心原因之一;
3. 记住:SpringBoot的核心就是“约定大于配置”,它帮我们做好了所有默认配置,我们只需要专注于业务逻辑。
明日预告
明天我们将学习:接口参数校验(避免非法参数)、全局异常处理(让接口更健壮),以及CRUD接口的优化(分页查询、条件查询),进一步完善我们的项目。
今天的学习就到这里啦,大家可以动手实操一遍CRUD接口,感受一下SpringBoot的便捷,同时好好理解Bean的原理——这是后续学习Spring的基础,吃透它,后面的学习会轻松很多~ 有问题可以在评论区留言,我们一起交流进步!
五、今日重点面试题(3道,贴合实操)
面试题1:GET和POST方法的区别(高频)
题干:在今日实现的CRUD接口中,我们用了GET(查询)、POST(新增)、DELETE(删除)、PUT(更新),请说明GET和POST的核心区别?
解析:核心区别有4点,贴合今日实操记忆更轻松:
-
1. 提交方式:GET请求参数拼接在URL上(如 http://localhost:8080/user/1 ),POST请求参数放在请求体中(如新增用户的JSON数据);
-
2. 安全性:GET参数暴露在URL,不适合传递敏感数据(如密码);POST参数隐藏在请求体,相对安全;
-
3. 长度限制:GET请求URL有长度限制(不同浏览器限制不同),POST无限制;
-
4. 语义与缓存:GET用于“查询”(无副作用,不修改数据),可被浏览器缓存;POST用于“提交/新增”(有副作用,修改数据),不被缓存。
面试题2:DO层和VO层的作用(贴合今日实体类)
题干:今日我们写的User实体类属于DO层,请问DO层和VO层分别是什么,各自的作用是什么?
解析:两者是SpringBoot项目中常用的分层实体,核心作用是解耦:
-
1. DO层(Data Object,数据对象):对应数据库表结构(如今日的User类),字段和数据库表字段一一对应,仅用于和数据库交互(存储、查询数据),不包含业务逻辑;
-
2. VO层(View Object,视图对象):用于前端和后端交互,仅包含前端需要展示/传递的字段(比如前端不需要展示createTime、updateTime,就可以在VO中省略),避免暴露数据库无关字段,提升安全性和简洁性。
面试题3:Controller层、Service层、Mapper层各自常用的注解有哪些?
题干:结合今日实现的CRUD接口,说明Controller层、Service层、Mapper层各自的核心注解及作用?
解析:对应今日代码,精准记忆:
-
1. Controller层:核心注解@RestController(等价于@Controller + @ResponseBody,用于标记控制层Bean,返回JSON数据)、@RequestMapping(定义接口统一前缀)、@GetMapping/@PostMapping等(指定请求方式);
-
2. Service层:核心注解@Service(标记服务层Bean,让Spring自动扫描管理),接口无需注解,实现类加@Service即可;
-
3. Mapper层:核心注解@Mapper(标记该接口是MyBatis的Mapper接口,SpringBoot自动扫描,用于数据库操作),无需写实现类,继承BaseMapper即可。
(注:文档部分内容可能由 AI 生成)

浙公网安备 33010602011771号