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工具测试接口,这里给出简单的测试示例:

测试成功后,就说明我们的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的整个过程,就像一个人的生命周期:

  1. 实例化:Spring创建Bean的实例(相当于new UserServiceImpl())

  2. 初始化:Spring对Bean进行初始化(比如设置属性、调用初始化方法)

  3. 使用:我们通过@Autowired拿到Bean,调用它的方法(比如userService.save(user))

  4. 销毁: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 生成)

posted @ 2026-04-21 23:44  白鹿为溪  阅读(50)  评论(0)    收藏  举报