【保姆级教程】Vue3 + Spring Boot + Element Plus 全栈开发实战:从0到1搭建用户管理系统
🔥【保姆级教程】Vue3 + Spring Boot + Element Plus 全栈开发实战:从0到1搭建用户管理系统
摘要:还在为不知道怎么开始写一个完整的Web项目而发愁吗?本文将带你从零开始,手把手教你搭建一个企业级的前后端分离项目。我们将使用目前最主流的技术栈:Spring Boot 作为后端,Vue 3 + Element Plus 作为前端。
你将学到:环境搭建、数据库设计、后端API接口开发、前端页面逻辑、前后端联调、跨域问题解决。
📅 更新时间:2025年
📂 项目源码:无
目录 (Table of Contents)
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 = “*”) 注解。这是开发环境最快的解决方式。
运行测试
- 启动 Spring Boot 应用(确保端口 9090 正常)。
- 在前端终端运行 npm run dev。
- 打开浏览器访问前端地址。
- 测试功能:尝试添加一条数据,看看列表是否自动刷新;查看 Navicat 数据库,数据是否已入库。
6. 📝 总结
恭喜你!🎉 经过以上步骤,你已经完成了一个从数据库到后端再到前端的完整 Web 项目。虽然它很小,但它包含了全栈开发最核心的流程:
- 数据库:设计表结构。
- 后端:RESTful API 设计,ORM 操作。
- 前端:组件化开发,网络请求,数据绑定。
💡 下一步建议:
尝试加入 Redis 缓存热点数据。
加入 JWT 登录认证 功能。
将代码部署到 Docker 容器中。
更多推荐


所有评论(0)