Spring Boot 实战(四):MySQL + MyBatis 接入,打通用户注册最小闭环

一、前言

前面三篇我们已经完成了:

  • Spring Boot 项目创建
  • Controller 接口开发
  • DTO 参数接收与校验
  • Service 分层
  • Result 统一返回
  • 全局异常处理
  • 日志

但目前还有一个核心问题:

数据没有真正落库

也就是说,现在的接口只是"能跑",但还不是真正的后端系统。

本篇开始,我们接入:

MySQL + MyBatis

把项目真正打通成:

Controller → Service → Mapper → MySQL

二、本篇目标

实现一个最小用户中心闭环:

  1. 用户注册(入库)

  2. 根据 ID 查询用户

  3. 根据 ID 删除用户

技术栈:

Spring Boot + MyBatis + MySQL


三、先加依赖

pom.xml 中加入这几个依赖。

html 复制代码
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.4</version>
</dependency>

<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

四、配置 application.yml

html 复制代码
server:
  port: 8080

spring:
  application:
    name: ark-backend

  datasource:
    url: jdbc:mysql://localhost:3306/user_center?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf-8
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: org.example.arkbackend.entity

logging:
  level:
    org.example.arkbackend: debug

五、先建数据库和表

1. 建库

sql 复制代码
CREATE DATABASE user_center DEFAULT CHARACTER SET utf8mb4;

2. 建表

sql 复制代码
CREATE TABLE user (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(64) NOT NULL,
password VARCHAR(128) NOT NULL,
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

六、项目结构调整

这一篇完成后,推荐最小结构如下:

复制代码
org.example.arkbackend
├── common
│   └── Result.java
├── controller
│   └── UserController.java
├── dto
│   └── UserRegisterDTO.java
├── entity
│   └── User.java
├── exception
│   └── GlobalExceptionHandler.java
├── mapper
│   └── UserMapper.java
├── service
│   ├── UserService.java
│   └── impl
│       └── UserServiceImpl.java
└── ArkBackendApplication.java

resources 目录下新增:

复制代码
resources
└── mapper
    └── UserMapper.xml

七、定义实体类

新建:

entity/User.java

java 复制代码
package org.example.arkbackend.entity;

import lombok.Data;

import java.time.LocalDateTime;

@Data
public class User {
private Long id;
private String username;
private String password;
private LocalDateTime createTime;
}

八、DTO 继续沿用

java 复制代码
package org.example.arkbackend.dto;

import jakarta.validation.constraints.NotBlank;
import lombok.Data;

@Data
public class UserRegisterDTO {

@NotBlank(message = "用户名不能为空")
private String username;

@NotBlank(message = "密码不能为空")
private String password;
}

九、定义 Mapper 接口

新建:

mapper/UserMapper.java

java 复制代码
package org.example.arkbackend.mapper;

import org.example.arkbackend.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface UserMapper {

int insert(User user);

User selectById(@Param("id") Long id);

int deleteById(@Param("id") Long id);

User selectByUsername(@Param("username") String username);
}

十、编写 Mapper XML

新建:

resources/mapper/UserMapper.xml

XML 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="org.example.arkbackend.mapper.UserMapper">

<resultMap id="UserResultMap" type="org.example.arkbackend.entity.User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="password" column="password"/>
<result property="createTime" column="create_time"/>
</resultMap>

<insert id="insert" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (username, password)
VALUES (#{username}, #{password})
</insert>

<select id="selectById" resultMap="UserResultMap">
SELECT id, username, password, create_time
FROM user
WHERE id = #{id}
</select>

<delete id="deleteById">
DELETE FROM user
WHERE id = #{id}
</delete>

<select id="selectByUsername" resultMap="UserResultMap">
SELECT id, username, password, create_time
FROM user
WHERE username = #{username}
LIMIT 1
</select>

</mapper>

十一、Service 接口

java 复制代码
package org.example.arkbackend.service;

import org.example.arkbackend.dto.UserRegisterDTO;
import org.example.arkbackend.entity.User;

public interface UserService {

String register(UserRegisterDTO dto);

User getUserById(Long id);

void deleteUser(Long id);
}

十二、Service 实现类

java 复制代码
package org.example.arkbackend.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.example.arkbackend.dto.UserRegisterDTO;
import org.example.arkbackend.entity.User;
import org.example.arkbackend.mapper.UserMapper;
import org.example.arkbackend.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class UserServiceImpl implements UserService {

@Autowired
private UserMapper userMapper;

@Override
public String register(UserRegisterDTO dto) {
log.info("开始注册用户:{}", dto.getUsername());

User existed = userMapper.selectByUsername(dto.getUsername());
if (existed != null) {
throw new RuntimeException("用户名已存在");
}

User user = new User();
user.setUsername(dto.getUsername());
user.setPassword(dto.getPassword());

userMapper.insert(user);

return "注册成功,用户ID:" + user.getId();
}

@Override
public User getUserById(Long id) {
log.info("查询用户:{}", id);

User user = userMapper.selectById(id);
if (user == null) {
throw new RuntimeException("用户不存在");
}

return user;
}

@Override
public void deleteUser(Long id) {
log.info("删除用户:{}", id);

int rows = userMapper.deleteById(id);
if (rows == 0) {
throw new RuntimeException("用户不存在,删除失败");
}
}
}

十三、Controller 改造

java 复制代码
package org.example.arkbackend.controller;

import jakarta.validation.Valid;
import org.example.arkbackend.common.Result;
import org.example.arkbackend.dto.UserRegisterDTO;
import org.example.arkbackend.entity.User;
import org.example.arkbackend.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/user")
public class UserController {

@Autowired
private UserService userService;

@PostMapping("/register")
public Result<String> register(@Valid @RequestBody UserRegisterDTO dto) {
return Result.success(userService.register(dto));
}

@GetMapping("/{id}")
public Result<User> getUser(@PathVariable Long id) {
return Result.success(userService.getUserById(id));
}

@DeleteMapping("/{id}")
public Result<Void> delete(@PathVariable Long id) {
userService.deleteUser(id);
return Result.success(null);
}
}

十四、统一返回结构

java 复制代码
package org.example.arkbackend.common;

import lombok.Data;

@Data
public class Result<T> {

private int code;
private String message;
private T data;

public static <T> Result<T> success(T data) {
Result<T> r = new Result<>();
r.setCode(0);
r.setMessage("成功");
r.setData(data);
return r;
}

public static <T> Result<T> fail(String message) {
Result<T> r = new Result<>();
r.setCode(1);
r.setMessage(message);
r.setData(null);
return r;
}
}

十五、全局异常处理

java 复制代码
package org.example.arkbackend.exception;

import org.example.arkbackend.common.Result;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(Exception.class)
public Result<?> handleException(Exception e) {
return Result.fail(e.getMessage());
}
}

十六、如何测试

1. 注册用户

POST /user/register

Content-Type: application/json

{

"username": "test",

"password": "123456"

}

返回示例:

{

"code": 0,

"message": "成功",

"data": "注册成功,用户ID:1"

}


2. 查询用户

GET /user/1

返回示例:

{

"code": 0,

"message": "成功",

"data": {

"id": 1,

"username": "test",

"password": "123456",

"createTime": "2026-04-16T10:30:00"

}

}

3. 删除用户

DELETE /user/1

返回示例:

{

"code": 0,

"message": "成功",

"data": null

}

十七、这一篇你真正掌握了什么

你现在打通的是:

Controller → Service → Mapper → MySQL

这意味着你已经从:会写接口

进入到了:会做最小后端项目

这一层非常关键。

十八、常见坑总结

1. 启动报数据库错误

原因通常是:

  • MySQL 没启动
  • 数据库不存在
  • 用户名密码错误
  • 没加 MySQL 驱动

2. Mapper 找不到

检查:

  • UserMapper.xml 路径是否在 resources/mapper
  • namespace 是否和接口全限定名一致
  • application.ymlmapper-locations 是否正确

3. 表字段映射不上

重点看:

create_time ↔ createTime

这种场景要么写 resultMap,要么开驼峰映射。


十九、一句话总结

MyBatis + MySQL 的接入,本质是把接口层和真实数据打通,让 Spring Boot 项目从"演示代码"变成"真正系统"

下一篇:

Spring Boot 实战(五):接口工程化升级(统一返回 + 异常处理 + 错误码体系 + 异常流转机制)

目标不是再加新功能,而是把"能跑的项目"升级成一个更像真实项目的工程化版本

相关推荐
架构源启2 小时前
深度解析:Spring Boot + Apache OpenNLP 构建企业级 NLU 系统
spring boot·后端·apache
han_hanker2 小时前
springboot / 若依 日志说明
java·spring boot·spring
我登哥MVP2 小时前
【SpringMVC笔记】 - 4 - 三个域对象
java·spring boot·spring·servlet·tomcat·maven·intellij-idea
阿丰资源11 小时前
基于SpringBoot的物流信息管理系统设计与实现(附资料)
java·spring boot·后端
星晨雪海13 小时前
Lombok 注解使用场景终极总结
java·数据库·mysql
hnmpf15 小时前
linux系统离线环境安装mysql问题
linux·运维·mysql
踏着七彩祥云的小丑15 小时前
云服务器——MySQL设置
服务器·mysql
lhbian15 小时前
PHP、C++和C语言对比:哪个更适合你?
android·数据库·spring boot·mysql·kafka
Dream of maid16 小时前
Mysql(9)事务
数据库·mysql