🔥【保姆级教程】Vue3 + Spring Boot + Element Plus 全栈开发实战:从0到1搭建用户管理系统

摘要:还在为不知道怎么开始写一个完整的Web项目而发愁吗?本文将带你从零开始,手把手教你搭建一个企业级的前后端分离项目。我们将使用目前最主流的技术栈:Spring Boot 作为后端,Vue 3 + Element Plus 作为前端。

你将学到:环境搭建、数据库设计、后端API接口开发、前端页面逻辑、前后端联调、跨域问题解决。

📅 更新时间:2025年
📂 项目源码:无


目录 (Table of Contents)

  1. 🛠️ 项目技术栈与准备工作
  2. 💾 第一步:数据库设计
  3. ☕ 第二步:后端开发 (Spring Boot)
  4. 🎨 第三步:前端开发 (Vue 3)
  5. 🔌 第四步:前后端联调与跨域
  6. 📝 总结与源码获取

1. 🛠️ 项目技术栈与准备工作

在开始写代码之前,我们要明确手里的“武器”。本项目采用经典的前后端分离架构。

1.1 技术选型

  • 前端:Vue 3 (Composition API) + Vite + Element Plus + Axios
  • 后端:Spring Boot 2.7+ / 3.0 + MyBatis Plus
  • 数据库:MySQL 8.0 / 5.7
  • 工具:IntelliJ IDEA, VS Code, Postman, Navicat

1.2 环境要求

确保你的电脑上已经安装了:

  • JDK 1.8 或 17
  • Node.js (建议 v16+)
  • MySQL

2. 💾 第一步:数据库设计

我们将做一个简单的 “用户管理系统”。主要功能是增删改查(CRUD)。

打开你的 Navicat 或 SQL 客户端,执行以下 SQL 语句:

sql
-- 创建数据库
CREATE DATABASE IF NOT EXISTS `crud_demo` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

USE `crud_demo`;

-- 创建用户表
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `username` varchar(50) NOT NULL COMMENT '用户名',
  `phone` varchar(20) DEFAULT NULL COMMENT '手机号',
  `email` varchar(50) DEFAULT NULL COMMENT '邮箱',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

-- 插入测试数据
INSERT INTO `sys_user` (`username`, `phone`, `email`) VALUES 
('张三', '13800138000', 'zhangsan@qq.com'),
('李四', '13900139000', 'lisi@163.com');

3. ☕ 第二步:后端开发 (Spring Boot)

后端负责提供 API 接口,只返回 JSON 数据,不负责页面渲染。

3.1 初始化项目

使用 IDEA 自带的 Spring Initializr 或访问 start.spring.io。
依赖勾选: Spring Web, MySQL Driver, Lombok, MyBatis-Plus Framework (需手动添加或在pom中引入).

3.2 配置 application.yml

server:
  port: 9090

spring:
  datasource:
    # 注意修改数据库名称和密码
    url: jdbc:mysql://localhost:3306/crud_demo?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
    username: root
    password: your_password 
    driver-class-name: com.mysql.cj.jdbc.Driver

# MyBatis Plus 配置:打印SQL日志
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

3.3 实体类 (Entity)

对应数据库中的表结构。

java
package com.example.demo.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
@TableName("sys_user")
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String username;
    private String phone;
    private String email;
    private LocalDateTime createTime;
}

3.4 Mapper 接口

得益于 MyBatis Plus,我们不需要写 XML,直接继承 BaseMapper 即可拥有强大的 CRUD 能力。

java
package com.example.demo.mapper;

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

@Mapper
public interface UserMapper extends BaseMapper<User> {
    // 基础增删改查方法已经自动注入,无需手写
}

3.5 Controller (接口层)

这是前端要调用的地方。
⚠️ 重点:@CrossOrigin 注解是解决开发环境跨域问题的关键!一定要加!

package com.example.demo.controller;

import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
@RequestMapping("/user")
@CrossOrigin(origins = "*") // 🚀 允许跨域请求
public class UserController {

    @Autowired
    private UserMapper userMapper;

    // 1. 查询所有用户
    @GetMapping("/list")
    public List<User> list() {
        return userMapper.selectList(null);
    }

    // 2. 新增用户
    @PostMapping("/save")
    public String save(@RequestBody User user) {
        userMapper.insert(user);
        return "新增成功";
    }

    // 3. 删除用户
    @DeleteMapping("/{id}")
    public String delete(@PathVariable Long id) {
        userMapper.deleteById(id);
        return "删除成功";
    }
}

4. 🎨 第三步:前端开发 (Vue 3)

我们将使用 Vite 快速构建,并引入 Element Plus 组件库。

4.1 初始化 Vue 项目

在终端 (CMD/PowerShell) 执行以下命令:

npm create vite@latest user-web -- --template vue
cd user-web
npm install
npm install element-plus axios

4.2 修改 main.js 引入 UI 库

import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'

const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')

4.3 编写核心页面 App.vue

我们将使用 Vue 3 的 Composition API (Script Setup 语法糖),代码非常简洁。

<template>
  <div class="app-container">
    <h1>👥 用户管理系统</h1>
    
    <!-- 顶部操作栏 -->
    <div class="header-box">
      <el-button type="primary" @click="dialogVisible = true">新增用户</el-button>
    </div>

    <!-- 表格区域 -->
    <el-table :data="tableData" border stripe style="width: 100%">
      <el-table-column prop="id" label="ID" width="80" />
      <el-table-column prop="username" label="用户名" />
      <el-table-column prop="phone" label="手机号" />
      <el-table-column prop="email" label="邮箱" />
      <el-table-column label="操作" width="120">
        <template #default="scope">
          <el-button type="danger" size="small" @click="handleDelete(scope.row.id)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>

    <!-- 弹窗区域 -->
    <el-dialog v-model="dialogVisible" title="添加用户" width="30%">
      <el-form :model="form" label-width="80px">
        <el-form-item label="用户名">
          <el-input v-model="form.username" />
        </el-form-item>
        <el-form-item label="手机号">
          <el-input v-model="form.phone" />
        </el-form-item>
        <el-form-item label="邮箱">
          <el-input v-model="form.email" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="saveUser">确定</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import axios from 'axios'
import { ElMessage, ElMessageBox } from 'element-plus'

// 后端接口地址
const API_BASE = 'http://localhost:9090/user'

const tableData = ref([])
const dialogVisible = ref(false)
const form = ref({ username: '', phone: '', email: '' })

// 1. 获取列表
const loadData = async () => {
  const res = await axios.get(`${API_BASE}/list`)
  tableData.value = res.data
}

// 2. 新增用户
const saveUser = async () => {
  if(!form.value.username) return ElMessage.warning('请输入用户名')
  
  await axios.post(`${API_BASE}/save`, form.value)
  ElMessage.success('操作成功')
  dialogVisible.value = false
  form.value = { username: '', phone: '', email: '' } // 重置表单
  loadData() // 刷新列表
}

// 3. 删除用户
const handleDelete = (id) => {
  ElMessageBox.confirm('确认删除吗?', '提示', { type: 'warning' })
    .then(async () => {
      await axios.delete(`${API_BASE}/${id}`)
      ElMessage.success('删除成功')
      loadData()
    })
    .catch(() => {})
}

// 页面加载完成时请求数据
onMounted(() => {
  loadData()
})
</script>

<style scoped>
.app-container {
  max-width: 1000px;
  margin: 50px auto;
  padding: 20px;
}
.header-box {
  margin-bottom: 20px;
}
</style>

5. 🔌 第四步:前后端联调与跨域

为什么会跨域?
前端运行在 localhost:5173 (Vite 默认端口),后端运行在 localhost:9090。浏览器出于安全策略,禁止不同端口的请求直接交互。
解决方案
我们在后端 UserController 上添加了 @CrossOrigin(origins = “*”) 注解。这是开发环境最快的解决方式。
运行测试

  1. 启动 Spring Boot 应用(确保端口 9090 正常)。
  2. 在前端终端运行 npm run dev。
  3. 打开浏览器访问前端地址。
  4. 测试功能:尝试添加一条数据,看看列表是否自动刷新;查看 Navicat 数据库,数据是否已入库。

6. 📝 总结

恭喜你!🎉 经过以上步骤,你已经完成了一个从数据库到后端再到前端的完整 Web 项目。虽然它很小,但它包含了全栈开发最核心的流程:

  1. 数据库:设计表结构。
  2. 后端:RESTful API 设计,ORM 操作。
  3. 前端:组件化开发,网络请求,数据绑定。

💡 下一步建议:
尝试加入 Redis 缓存热点数据。
加入 JWT 登录认证 功能。
将代码部署到 Docker 容器中。

Logo

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

更多推荐