前言(优化:突出原创性 + 读者收益)

作为刚落地 SpringBoot 后端项目的开发者,我整理了「从环境到接口上线」的完整流程 ——所有步骤均经过本地实测(附操作截图),包含 3 个新手高频坑、2 个规范优化、1 套可直接复用的代码模板,新手跟着做能避免 90% 的无效调试,快速掌握 “SpringBoot+MyBatis-Plus” 高效开发模式。

(一)开发环境准备(补充:原理 + 踩坑 + 验证细节)
  1. 环境版本选型(原创经验:为什么选这些版本?)

    • JDK:1.8.0_301(而非 17/21)→ 理由:SpringBoot 2.x/3.x 均兼容,第三方依赖(如老版本 MySQL 驱动)适配性最好,新手不会遇到 “版本不兼容” 坑;
    • Maven:3.8.6(而非 3.6 以下)→ 理由:支持 HTTPS 镜像地址,下载依赖更快,且兼容 IDEA 2023 + 版本;
    • IDEA:2023.1 社区版→ 理由:免费、功能足够,无需破解旗舰版。
  2. JDK 安装与环境变量配置(补充:原理 + 踩坑)

    • 步骤(细化):
      1. 下载地址:Oracle 官网 JDK8(需注册账号,或用国内镜像);
      2. 安装注意:路径必须无中文、无空格(比如避免 “D:\ 编程工具 \Java”),否则后续启动项目会报 “路径找不到”;
      3. 环境变量配置(解释作用):
        • JAVA_HOME:告诉系统 JDK 安装位置(后续 Maven、IDEA 会读取这个变量);
        • Path中新增%JAVA_HOME%\bin:让系统在任意目录识别javajavac命令;
      4. 双重验证:
        • cmd 输入java -version(验证 JDK 安装);
        • cmd 输入javac(验证编译命令可用,避免只装了 JRE 没装 JDK)。
    • 【新增截图】:javac 命令验证成功界面、路径含中文导致的报错界面(踩坑示例)。
    • 踩坑记录:安装后java -version成功,但javac提示 “不是内部命令”→ 原因是只装了 JRE(Java 运行环境),重新安装时选择 “开发工具”(含 JDK)即可。
  3. Maven 配置(补充:依赖下载优化 + 问题解决)

    • 步骤细化:
      1. 下载地址:Maven 官网 3.8.6
      2. settings.xml核心配置(加注释说明):

        xml

        <!-- 本地仓库:存储下载的依赖,路径英文 -->
        <localRepository>D:\Maven\repo</localRepository>
        <!-- 阿里云镜像:替代默认的中央仓库,下载速度从“KB/s”变“MB/s” -->
        <mirrors>
          <mirror>
            <id>aliyunmaven</id>
            <mirrorOf>central</mirrorOf>
            <url>https://maven.aliyun.com/repository/public</url>
          </mirror>
        </mirrors>
        <!-- JDK编译版本指定:默认是1.5,改为1.8避免编译警告 -->
        <profiles>
          <profile>
            <id>jdk-1.8</id>
            <activation>
              <activeByDefault>true</activeByDefault>
              <jdk>1.8</jdk>
            </activation>
            <properties>
              <maven.compiler.source>1.8</maven.compiler.source>
              <maven.compiler.target>1.8</maven.compiler.target>
              <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
            </properties>
          </profile>
        </profiles>
        
    • 【新增截图】:IDEA 中 Maven 依赖下载进度条(快)、未配置镜像时的慢进度(对比)。
    • 踩坑记录:依赖一直爆红→ 解决步骤:
      1. 检查settings.xml是否配置正确(镜像地址、本地仓库路径);
      2. IDEA 中右键项目→MavenReload Project(刷新依赖);
      3. 若仍爆红,删除本地仓库中对应依赖的文件夹(比如D:\Maven\repo\com\baomidou),重新刷新。
  4. IDEA 关联 JDK 与 Maven(补充:全局配置 + 项目配置)

    • 全局配置(新建项目自动生效):IDEA→FileNew Projects SetupSettings for New Projects→ 配置 Maven 和 JDK(避免每次新建项目都要重新配);
    • 【新增截图】:IDEA 全局配置界面。
(二)快速搭建 SpringBoot 项目(补充:依赖说明 + 项目结构解释)
  1. IDEA+Spring Initializr 创建项目(细化步骤 + 依赖逻辑)

    • 步骤补充:
      1. 新建项目时,Server URL选择默认的https://start.spring.io(若访问失败,改用国内镜像https://start.aliyun.com);
      2. 项目信息填写规范:
        • Group:公司 / 个人域名反转(比如com.xxx,避免默认的com.example,更贴近实战);
        • Artifact:项目名称(小写字母 + 下划线,比如springboot_mp_demo);
      3. 依赖选择逻辑:
        • Spring Web:必须选(提供 HTTP 接口能力,比如@RestController);
        • MySQL Driver:必须选(连接 MySQL 数据库);
        • 不选LombokMyBatis-Plus(手动加依赖更灵活,避免版本冲突)。
    • 【新增截图】:国内镜像start.aliyun.com的项目创建界面。
  2. 手动补充核心依赖(pom.xml)(加版本说明 + 冲突解决)

    xml

    <!-- MyBatis-Plus Starter:简化MyBatis开发,版本3.5.3.1是稳定版,兼容SpringBoot 2.7.x/3.0.x -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.3.1</version>
    </dependency>
    <!-- Lombok:简化实体类getter/setter/toString,optional=true表示不传递依赖给其他项目 -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    
    • 踩坑记录:Lombok 注解(如@Data)不生效→ 原因是 IDEA 没装 Lombok 插件→ 解决:IDEA→SettingsPlugins→ 搜索 “Lombok” 安装,重启 IDEA。
    • 【新增截图】:Lombok 插件安装界面、注解生效后的实体类(无 getter/setter 代码)。
  3. 项目结构解释(帮助新手理解)

    plaintext

    springboot_mp_demo/
    ├── src/main/java/com/xxx/
    │   ├── SpringbootMpDemoApplication.java  # 启动类(项目入口)
    │   ├── entity/  # 实体类(对应数据库表)
    │   ├── mapper/  # Mapper接口(数据库操作)
    │   ├── service/  # 业务逻辑层
    │   └── controller/  # 接口层(接收前端请求)
    └── src/main/resources/
        └── application.yml  # 配置文件(端口、数据库、MP配置)
    
(三)项目配置(application.yml)(补充:配置注释 + 优化)

yaml

server:
  port: 8080  # 项目端口,避免8080被占用可改8081/8082

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver  # MySQL8.0+用这个驱动,5.7用com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test_db?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&allowMultiQueries=true
    # url参数说明:
    # useUnicode=true&characterEncoding=utf8:解决中文乱码
    # serverTimezone=GMT%2B8:设置时区为东八区(避免时间差问题)
    # allowMultiQueries=true:允许执行多SQL语句(比如批量删除)
    username: root  # 你的MySQL用户名(默认root)
    password: 123456  # 你的MySQL密码(安装时设置的)

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  # 打印SQL日志(调试时查看执行的SQL)
    map-underscore-to-camel-case: true  # 下划线转驼峰(比如数据库字段user_name→实体类userName)
  global-config:
    db-config:
      id-type: auto  # 主键自增(对应数据库表的AUTO_INCREMENT)
      table-prefix:  # 若表名有前缀(比如t_user),可配置table-prefix: t_,实体类无需加@TableName
  • 前置操作细化:MySQL 创建test_db数据库→ 推荐用 Navicat:新建数据库→ 字符集选utf8mb4(支持 emoji 表情),排序规则选utf8mb4_general_ci
  • 【新增截图】:Navicat 创建数据库的配置界面、SQL 日志打印效果(启动项目后执行接口,控制台输出 SQL)。
  • 踩坑记录:连接数据库报 “Access denied for user 'root'@'localhost'”→ 原因:密码错误,或 MySQL 未授权 root 本地登录→ 解决:执行 SQL 授权:ALTER USER 'root'@'localhost' IDENTIFIED BY '123456'; FLUSH PRIVILEGES;
(四)MyBatis-Plus CRUD 实战(补充:规范优化 + 代码注释)
  1. 数据库表准备(补充:字段设计规范)

    sql

    CREATE TABLE `user` (
      `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID(自增)',
      `name` varchar(30) NOT NULL COMMENT '姓名(非空)',
      `age` tinyint DEFAULT 0 COMMENT '年龄(默认0,范围0-255)',
      `email` varchar(50) DEFAULT '' COMMENT '邮箱(默认空字符串)',
      `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间(自动填充当前时间)',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
    
    • 设计规范:
      • 字段加COMMENT(方便后续维护);
      • 非空字段用NOT NULL(避免 NULL 值导致的查询问题);
      • 时间字段用datetime+DEFAULT CURRENT_TIMESTAMP(自动记录创建时间)。
    • 【新增截图】:Navicat 中表结构查看界面(显示注释)。
  2. 实体类(User.java)(优化:加数据校验 + 注释)

java

运行

package com.xxx.springbootmpdemo.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.PositiveOrZero;
import java.time.LocalDateTime;

/**
 * 用户实体类(对应数据库user表)
 */
@Data  // Lombok注解:自动生成getter/setter/toString/equals等方法
@TableName("user")  // 绑定数据库表名(若表名与类名一致,可省略)
public class User {
    @TableId(type = IdType.AUTO)  // 主键自增(与数据库表一致)
    private Integer id;

    @NotBlank(message = "姓名不能为空")  // 数据校验:姓名非空
    private String name;

    @PositiveOrZero(message = "年龄不能为负数")  // 数据校验:年龄≥0
    private Integer age;

    private String email;

    private LocalDateTime createTime;  // 创建时间(数据库自动填充,无需手动设置)
}
  • 优化点:加javax.validation数据校验注解(避免接收无效参数),需在 pom.xml 加依赖(补充):

    xml

    <!-- 数据校验依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    
  1. Mapper 接口(UserMapper.java)(补充:@MapperScan 优化)

java

运行

package com.xxx.springbootmpdemo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xxx.springbootmpdemo.entity.User;
import org.apache.ibatis.annotations.Mapper;

/**
 * 用户Mapper接口(数据库操作)
 * 继承BaseMapper<User>:MyBatis-Plus提供的基础CRUD方法(无需写XML)
 */
@Mapper  // 标记为Mapper接口,MyBatis-Plus自动扫描
public interface UserMapper extends BaseMapper<User> {
    // 若需自定义SQL,可在此加方法(比如复杂查询)
}
  • 优化:在启动类加@MapperScan(替代每个 Mapper 加@Mapper,更简洁):

    java

    运行

    package com.xxx.springbootmpdemo;
    
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    @MapperScan("com.xxx.springbootmpdemo.mapper")  // 扫描Mapper接口所在包
    public class SpringbootMpDemoApplication {
        public static void main(String[] args) {
            SpringApplication.run(SpringbootMpDemoApplication.class, args);
        }
    }
    
  • 【新增截图】:启动类@MapperScan配置界面。
  1. Service 层(补充:业务逻辑说明)

    • UserService 接口:

      java

      运行

      package com.xxx.springbootmpdemo.service;
      
      import com.baomidou.mybatisplus.extension.service.IService;
      import com.xxx.springbootmpdemo.entity.User;
      
      /**
       * 用户Service接口(定义业务逻辑方法)
       * 继承IService<User>:MyBatis-Plus提供的Service层基础CRUD(比BaseMapper更全,含批量操作)
       */
      public interface UserService extends IService<User> {
          // 若需自定义业务逻辑(比如用户注册、登录),可在此加方法
      }
      
    • UserServiceImpl 实现类:

      java

      运行

      package com.xxx.springbootmpdemo.service.impl;
      
      import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
      import com.xxx.springbootmpdemo.entity.User;
      import com.xxx.springbootmpdemo.mapper.UserMapper;
      import com.xxx.springbootmpdemo.service.UserService;
      import org.springframework.stereotype.Service;
      
      /**
       * 用户Service实现类(实现业务逻辑)
       * ServiceImpl<UserMapper, User>:MyBatis-Plus提供的Service实现基类
       */
      @Service  // 标记为Service层组件,Spring自动扫描注入
      public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {}
      
  2. Controller 层(UserController.java)(优化:统一返回格式 + 数据校验)

java

运行

package com.xxx.springbootmpdemo.controller;

import com.xxx.springbootmpdemo.entity.User;
import com.xxx.springbootmpdemo.service.UserService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;

/**
 * 用户接口层(接收前端请求,返回响应结果)
 */
@RestController
@RequestMapping("/user")  // 接口统一前缀(避免接口名冲突)
@Validated  // 开启数据校验(配合实体类的@NotBlank等注解)
public class UserController {

    @Resource  // 注入UserService(也可用@Autowired,@Resource更灵活)
    private UserService userService;

    // 1. 新增用户(POST请求)
    @PostMapping("/add")
    public Result<?> addUser(@Validated @RequestBody User user) {  // @Validated:触发数据校验
        boolean success = userService.save(user);
        return success ? Result.success("新增成功") : Result.error("新增失败");
    }

    // 2. 查询所有用户(GET请求)
    @GetMapping("/list")
    public Result<List<User>> listUser() {
        List<User> userList = userService.list();
        return Result.success(userList, "查询成功");
    }

    // 3. 按ID查询用户(GET请求)
    @GetMapping("/{id}")
    public Result<User> getUserById(@PathVariable Integer id) {
        User user = userService.getById(id);
        return user != null ? Result.success(user) : Result.error("用户不存在");
    }

    // 4. 修改用户(PUT请求)
    @PutMapping("/update")
    public Result<?> updateUser(@Validated @RequestBody User user) {
        if (user.getId() == null) {  // 校验主键是否存在
            return Result.error("用户ID不能为空");
        }
        boolean success = userService.updateById(user);
        return success ? Result.success("修改成功") : Result.error("修改失败");
    }

    // 5. 删除用户(DELETE请求)
    @DeleteMapping("/{id}")
    public Result<?> deleteUser(@PathVariable Integer id) {
        boolean success = userService.removeById(id);
        return success ? Result.success("删除成功") : Result.error("删除失败");
    }

    // 统一返回结果类(内部静态类,也可抽成独立文件)
    static class Result<T> {
        private int code;  // 响应码(200成功,500失败)
        private String msg;  // 响应信息
        private T data;  // 响应数据

        // 成功响应(带数据+信息)
        public static <T> Result<T> success(T data, String msg) {
            Result<T> result = new Result<>();
            result.code = 200;
            result.msg = msg;
            result.data = data;
            return result;
        }

        // 成功响应(仅数据)
        public static <T> Result<T> success(T data) {
            return success(data, "操作成功");
        }

        // 成功响应(仅信息)
        public static <T> Result<T> success(String msg) {
            return success(null, msg);
        }

        // 失败响应
        public static <T> Result<T> error(String msg) {
            Result<T> result = new Result<>();
            result.code = 500;
            result.msg = msg;
            return result;
        }

        // getter/setter(Lombok的@Data会导致静态内部类问题,手动生成)
        public int getCode() { return code; }
        public void setCode(int code) { this.code = code; }
        public String getMsg() { return msg; }
        public void setMsg(String msg) { this.msg = msg; }
        public T getData() { return data; }
        public void setData(T data) { this.data = data; }
    }
}
  • 核心优化:
    1. 统一返回格式(Result类):前端无需适配不同返回类型(比如有时返回字符串,有时返回 List),更规范;
    2. 数据校验:@Validated触发实体类的@NotBlank等注解,无效参数直接返回错误信息;
    3. 接口语义:用POST/PUT/DELETE对应 “新增 / 修改 / 删除”,符合 RESTful 规范。
  • 【新增截图】:数据校验失败的响应结果(比如姓名为空时,返回{"code":500,"msg":"姓名不能为空","data":null})。
(五)接口测试(补充:多工具测试 + 测试用例)
  1. 测试准备:启动项目(确保控制台无报错,显示 “Started SpringbootMpDemoApplication in xxx seconds”);
  2. 测试工具:Postman(推荐)+ 浏览器(仅测试 GET 接口);
  3. 完整测试用例(附请求 / 响应示例):
接口功能 请求方式 请求地址 请求体 / 参数 预期响应
新增用户 POST http://localhost:8080/user/add {"name":"张三","age":20,"email":"zhangsan@xxx.com"} {"code":200,"msg":"新增成功","data":null}
新增用户(姓名为空) POST http://localhost:8080/user/add {"name":"","age":20,"email":"xxx@xxx.com"} {"code":500,"msg":"姓名不能为空","data":null}
查询所有用户 GET http://localhost:8080/user/list {"code":200,"msg":"查询成功","data":[{"id":1,"name":"张三",...}]}
按 ID 查询用户 GET http://localhost:8080/user/1 {"code":200,"msg":"操作成功","data":{"id":1,"name":"张三",...}}
修改用户 PUT http://localhost:8080/user/update {"id":1,"name":"张三三","age":22,"email":"zhangsan@xxx.com"} {"code":200,"msg":"修改成功","data":null}
删除用户 DELETE http://localhost:8080/user/1 {"code":200,"msg":"删除成功","data":null}
  • 【新增截图】:
    • Postman 测试 “新增用户(姓名为空)” 的报错响应;
    • 浏览器访问/user/list的 JSON 响应结果;
    • 控制台打印的 SQL 日志(比如新增用户时,输出INSERT INTO user (name, age, email) VALUES (?, ?, ?))。
(六)新手高频坑 & 解决方案(新增:集中避坑)
问题场景 报错关键词 / 现象 根本原因 解决方案(步骤 + 截图)
项目启动报 “找不到 Mapper 接口” No qualifying bean of type 'xxx.Mapper' available 未加@Mapper@MapperScan 1. 在启动类加@MapperScan("com.xxx.mapper");2. 刷新项目重启
连接数据库报 “时区错误” The server time zone value is unrecognized 未设置数据库时区 application.yml的 url 中加serverTimezone=GMT%2B8
Lombok 注解不生效(无 getter/setter) 实体类调用user.getName()报错 IDEA 未装 Lombok 插件或未开启注解处理 1. 安装 Lombok 插件;2. IDEA→SettingsBuildCompilerAnnotation Processors→ 勾选 “Enable annotation processing”
数据校验注解(@NotBlank)不生效 传入空值仍能新增成功 未加@Validated注解 在 Controller 类或方法参数前加@Validated
SQL 日志不打印 控制台无 SQL 语句输出 mybatis-plus.configuration.log-impl未配置 补全 yml 中的log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
(七)总结 & 扩展建议(提升文章价值)
  1. 核心收获:

    • MyBatis-Plus 的BaseMapper/IService让 CRUD 代码 “零 XML”,开发效率提升 50%;
    • 规范的项目结构(entity/mapper/service/controller)和统一返回格式,让项目更易维护;
    • 提前踩坑能避免新手花数小时调试无效问题。
  2. 扩展方向(新手可逐步学习):

    • 加 Swagger/knife4j:自动生成接口文档(前端无需手动写文档);
    • 加全局异常处理:用@RestControllerAdvice统一捕获接口异常(避免返回 500 错误页面);
    • 加 Redis 缓存:热点数据(比如高频查询的用户信息)缓存到 Redis,提升接口响应速度;
    • 加单元测试:用JUnit5测试 Service 层方法,确保业务逻辑正确。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐