从零开始复现 learning-demo 项目 - Spring Boot 全栈实战指南

星期四, 4月 9, 2026 | 5分钟阅读 | 更新于 星期四, 4月 9, 2026

@

前言

这篇文章教你从零开始,一步步复现 learning-demo 项目。每一步都有代码,照着做就能跑起来。


第一步:创建 Spring Boot 项目

1.1 使用 Spring Initializr 创建

打开 https://start.spring.io ,填写:

项目
ProjectMaven
LanguageJava
Spring Boot3.2.5
Groupcom.demo
Artifactlearning-demo-backend
Namelearning-demo-backend
Package namecom.demo
PackagingJar
Java17

点击「ADD DEPENDENCIES」,添加:

  • Spring Web
  • Spring Data JDBC
  • MySQL Driver
  • Lombok

点击「GENERATE」,下载 zip 文件,解压到你的工作目录。

1.2 项目结构

解压后是这样的:

learning-demo-backend/
├── src/
│   ├── main/
│   │   ├── java/com/demo/
│   │   │   └── DemoApplication.java    ← 启动类
│   │   └── resources/
│   │       └── application.properties  ← 配置文件(先删掉,用 yml)
│   └── test/
├── pom.xml                              ← Maven 配置

第二步:配置 pom.xml 依赖

打开 pom.xml,把 <dependencies> 部分改成这样:

<dependencies>
    <!-- Web:提供 REST API -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- JDBC:数据库连接池 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>

    <!-- MySQL 驱动 -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <scope>runtime</scope>
    </dependency>

    <!-- MyBatis-Plus:比 MyBatis 更好用 -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
        <version>3.5.6</version>
    </dependency>

    <!-- Redis:缓存 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

    <!-- Kafka:消息队列 -->
    <dependency>
        <groupId>org.springframework.kafka</groupId>
        <artifactId>spring-kafka</artifactId>
    </dependency>

    <!-- Lombok:少写 getter/setter -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <scope>provided</scope>
    </dependency>
</dependencies>

第三步:配置 application.yml

删掉 application.properties,新建 application.yml

server:
  port: 8080

spring:
  application:
    name: learning-demo

  # 数据库配置
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/learning_demo?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
    username: root
    password: root123    # 改成你的密码

  # Redis 配置
  data:
    redis:
      host: localhost
      port: 6379

  # Kafka 配置
  kafka:
    bootstrap-servers: localhost:9092
    consumer:
      group-id: demo-group
      auto-offset-reset: earliest
    producer:
      acks: "1"

# MyBatis-Plus 配置
mybatis-plus:
  mapper-locations: classpath*:mapper/**/*.xml
  configuration:
    map-underscore-to-camel-case: true

第四步:创建数据库

4.1 创建数据库

打开 MySQL,执行:

CREATE DATABASE learning_demo;

4.2 创建用户表

USE learning_demo;

CREATE TABLE t_user (
    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '用户ID',
    username VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名',
    password VARCHAR(100) NOT NULL COMMENT '密码',
    email VARCHAR(100) COMMENT '邮箱',
    status TINYINT DEFAULT 1 COMMENT '状态:1正常,0禁用',
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
);

-- 插入测试数据
INSERT INTO t_user (username, password, email) VALUES
    ('admin', '123456', 'admin@example.com'),
    ('zhangsan', '123456', 'zhangsan@example.com');

第五步:创建实体类 Entity

新建 src/main/java/com/demo/entity/User.java

package com.demo.entity;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;

@Data                    // Lombok 自动生成 getter/setter
@TableName("t_user")     // 对应数据库表名
public class User {
    private Long id;
    private String username;
    private String password;
    private String email;
    private Integer status;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;
}

第六步:创建 Mapper 接口

新建 src/main/java/com/demo/mapper/UserMapper.java

package com.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;

@Mapper
public interface UserMapper extends BaseMapper<User> {
    // 继承 BaseMapper 后,自动拥有:
    // - selectById(id)      查单个
    // - selectList()        查列表
    // - insert(user)        插入
    // - updateById(user)    更新
    // - deleteById(id)      删除

    // 自定义查询
    @Select("SELECT * FROM t_user WHERE username = #{username}")
    List<User> selectByUsername(String username);
}

第七步:创建 Service 层

新建 src/main/java/com/demo/service/UserService.java

package com.demo.service;

import com.demo.entity.User;
import java.util.List;

public interface UserService {
    User getById(Long id);
    List<User> getAll();
    User register(String username, String password, String email);
    User update(Long id, String email);
    boolean delete(Long id);
}

新建 src/main/java/com/demo/service/impl/UserServiceImpl.java

package com.demo.service.impl;

import com.demo.entity.User;
import com.demo.mapper.UserMapper;
import com.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public User getById(Long id) {
        return userMapper.selectById(id);
    }

    @Override
    public List<User> getAll() {
        return userMapper.selectList(null);
    }

    @Override
    public User register(String username, String password, String email) {
        // 检查用户名是否已存在
        List<User> existing = userMapper.selectByUsername(username);
        if (!existing.isEmpty()) {
            throw new RuntimeException("用户名已存在");
        }

        User user = new User();
        user.setUsername(username);
        user.setPassword(password);  // 生产环境要加密!
        user.setEmail(email);
        user.setStatus(1);

        userMapper.insert(user);
        return user;
    }

    @Override
    public User update(Long id, String email) {
        User user = userMapper.selectById(id);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }
        user.setEmail(email);
        userMapper.updateById(user);
        return user;
    }

    @Override
    public boolean delete(Long id) {
        return userMapper.deleteById(id) > 0;
    }
}

第八步:创建 Controller 层

新建 src/main/java/com/demo/controller/UserController.java

package com.demo.controller;

import com.demo.entity.User;
import com.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserService userService;

    // 查所有用户
    @GetMapping
    public List<User> getAll() {
        return userService.getAll();
    }

    // 查单个用户
    @GetMapping("/{id}")
    public User getById(@PathVariable Long id) {
        return userService.getById(id);
    }

    // 注册
    @PostMapping("/register")
    public User register(@RequestBody User user) {
        return userService.register(
            user.getUsername(),
            user.getPassword(),
            user.getEmail()
        );
    }

    // 更新
    @PutMapping("/{id}")
    public User update(@PathVariable Long id, @RequestBody User user) {
        return userService.update(id, user.getEmail());
    }

    // 删除
    @DeleteMapping("/{id}")
    public String delete(@PathVariable Long id) {
        userService.delete(id);
        return "删除成功";
    }
}

第九步:统一返回格式

新建 src/main/java/com/demo/common/Result.java

package com.demo.common;

import lombok.Data;

@Data
public class Result<T> {
    private Integer code;    // 200 成功,其他失败
    private String message;
    private T data;

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

    public static <T> Result<T> error(String message) {
        Result<T> result = new Result<>();
        result.setCode(500);
        result.setMessage(message);
        return result;
    }
}

修改 Controller,用 Result 包装返回值:

@GetMapping
public Result<List<User>> getAll() {
    return Result.success(userService.getAll());
}

第十步:添加 Redis 缓存

新建 src/main/java/com/demo/redis/UserCacheService.java

package com.demo.redis;

import com.demo.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;

@Service
public class UserCacheService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // 缓存用户,有效期 30 分钟
    public void cacheUser(Long id, User user) {
        String key = "user:" + id;
        redisTemplate.opsForValue().set(key, user, 30, TimeUnit.MINUTES);
    }

    // 从缓存取用户
    public User getUser(Long id) {
        String key = "user:" + id;
        return (User) redisTemplate.opsForValue().get(key);
    }

    // 删除缓存
    public void deleteUser(Long id) {
        String key = "user:" + id;
        redisTemplate.delete(key);
    }
}

在 Service 里用缓存:

@Override
public User getById(Long id) {
    // 先查缓存
    User cached = userCacheService.getUser(id);
    if (cached != null) {
        return cached;
    }

    // 缓存没有,查数据库
    User user = userMapper.selectById(id);
    if (user != null) {
        userCacheService.cacheUser(id, user);  // 存到缓存
    }
    return user;
}

第十一步:添加 Kafka 消息

新建 src/main/java/com/demo/kafka/UserKafkaProducer.java

package com.demo.kafka;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

@Service
public class UserKafkaProducer {

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    private static final String TOPIC = "user-events";

    // 发送消息
    public void sendUserRegistered(String username) {
        String message = "新用户注册:" + username;
        kafkaTemplate.send(TOPIC, message);
    }
}

新建 src/main/java/com/demo/kafka/UserKafkaConsumer.java

package com.demo.kafka;

import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Service;

@Service
public class UserKafkaConsumer {

    // 监听消息
    @KafkaListener(topics = "user-events", groupId = "demo-group")
    public void consume(String message) {
        System.out.println("收到消息:" + message);
        // 可以在这里做其他事情,比如发欢迎邮件
    }
}

在注册时发送消息:

@Autowired
private UserKafkaProducer kafkaProducer;

@Override
public User register(String username, String password, String email) {
    // ... 注册逻辑 ...

    // 发送 Kafka 消息
    kafkaProducer.sendUserRegistered(username);

    return user;
}

第十二步:启动测试

12.1 启动依赖服务

确保这些服务在运行:

  • MySQL:localhost:3306
  • Redis:localhost:6379
  • Kafka:localhost:9092

12.2 运行项目

mvn spring-boot:run

12.3 测试 API

用浏览器或 curl 测试:

# 查所有用户
curl http://localhost:8080/api/users

# 注册新用户
curl -X POST http://localhost:8080/api/users/register \
  -H "Content-Type: application/json" \
  -d '{"username":"test","password":"123456","email":"test@example.com"}'

# 查单个用户
curl http://localhost:8080/api/users/1

# 删除用户
curl -X DELETE http://localhost:8080/api/users/1

总结

从零到完整项目,一共 12 步:

步骤做了什么
1创建 Spring Boot 项目
2配置 pom.xml 依赖
3配置 application.yml
4创建数据库和表
5创建 Entity 实体类
6创建 Mapper 接口
7创建 Service 层
8创建 Controller 层
9统一返回格式 Result
10添加 Redis 缓存
11添加 Kafka 消息
12启动测试

这就是 learning-demo 后端的核心部分。前端 Vue 3 部分可以参考项目解读那篇文章。

© 2026 My Blog

🌱 Powered by Hugo with theme Dream.