首页
/ 【2025最新版】SpringBoot3+Vue3全栈开发脚手架实战指南:从0到1搭建企业级应用架构

【2025最新版】SpringBoot3+Vue3全栈开发脚手架实战指南:从0到1搭建企业级应用架构

2026-02-04 04:22:16作者:钟日瑜

开篇:为什么这个全栈脚手架能让你开发效率提升300%?

你是否还在为这些问题困扰:

  • 新项目搭建时,前后端整合要浪费3天以上?
  • JWT认证、权限管理重复造轮子?
  • Vue3组合式API与后端接口对接总是踩坑?
  • 跨域配置、文件上传、数据校验这些"基础建设"占用大量开发时间?

读完本文你将获得

  • 一套开箱即用的SpringBoot3+Vue3全栈架构方案
  • 10分钟快速启动前后端开发环境的实操步骤
  • 5个企业级功能模块的完整实现代码(用户认证/权限管理/数据CRUD/文件上传/图表展示)
  • 3种环境(开发/测试/生产)的无缝切换配置
  • 10+个实战踩坑点与性能优化技巧

项目架构全景解析

技术栈选型对比表

技术领域 本项目方案 传统方案 优势说明
后端框架 Spring Boot 3 Spring Boot 2.x 支持JDK17+,性能提升20%,原生支持虚拟线程
前端框架 Vue 3 + Vite Vue 2 + Webpack 冷启动速度提升10倍,热更新速度提升5倍
数据库访问 MyBatis-Plus 原生MyBatis 内置CRUD接口,减少70%重复代码
认证机制 JWT (JSON Web Token) Session-Cookie 无状态设计,支持分布式部署,减轻服务器压力
前端UI Element Plus Element UI 基于Vue3开发,支持按需引入,体积减少40%

系统架构流程图

flowchart TD
    Client[用户浏览器] --> |HTTP请求| Vue3Frontend[Vue3前端应用]
    Vue3Frontend --> |API调用| SpringBootBackend[SpringBoot3后端服务]
    SpringBootBackend --> |认证校验| JWTFilter[JWT过滤器]
    JWTFilter --> |权限检查| SecurityConfig[Spring Security配置]
    SecurityConfig --> |业务逻辑| Controller[控制器层]
    Controller --> |数据处理| Service[服务层]
    Service --> |数据库操作| Mapper[MyBatis-Plus映射层]
    Mapper --> MySQL[(MySQL数据库)]
    Service --> |缓存操作| LocalCache[本地缓存]
    Controller --> |文件处理| FileUpload[文件上传服务]
    FileUpload --> FileSystem[(文件系统)]

核心功能模块详解

1. 用户认证与权限管理

数据模型设计

-- 用户表结构
CREATE TABLE `sys_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL COMMENT '登录账号',
  `password` varchar(255) NOT NULL COMMENT '加密密码',
  `nickname` varchar(255) DEFAULT NULL COMMENT '用户昵称',
  `avatar` varchar(255) DEFAULT NULL COMMENT '头像URL',
  `sex` char(1) DEFAULT NULL COMMENT '性别(0:男,1:女)',
  `phone` varchar(11) DEFAULT NULL COMMENT '手机号',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 角色表结构
CREATE TABLE `sys_role` (
  `id` bigint(20) NOT NULL,
  `role_name` varchar(255) DEFAULT NULL COMMENT '角色名称',
  `role_key` varchar(255) DEFAULT NULL COMMENT '角色标识',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 用户角色关联表
CREATE TABLE `sys_user_role` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) DEFAULT NULL,
  `role_id` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

JWT认证实现代码

后端JWT工具类

@Component
public class JwtUtils {
    @Value("${jwt.secret}")
    private String secret;
    
    @Value("${jwt.expiration}")
    private long expiration;
    
    // 生成token
    public String generateToken(LoginUser loginUser) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", loginUser.getId());
        claims.put("username", loginUser.getUsername());
        claims.put("roles", loginUser.getRoles());
        
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }
    
    // 从token中获取用户信息
    public Claims getClaimsFromToken(String token) {
        return Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody();
    }
    
    // 验证token是否过期
    public boolean isTokenExpired(String token) {
        Date expiration = getClaimsFromToken(token).getExpiration();
        return expiration.before(new Date());
    }
}

前端请求拦截器

// 请求拦截器
instance.interceptors.request.use((config) => {
    const token = localStorage.getItem("token");
    // 白名单外的请求添加token
    if (whiteList.indexOf(config.url) === -1 && token) {
        config.headers['Authorization'] = token;
    }
    return config;
}, (error) => {
    return Promise.reject(error);
});

2. 数据CRUD接口实现

以演示数据(Demo)模块为例,展示完整的前后端交互流程:

后端Controller层

@RestController
@RequestMapping("/demo")
public class DemoController {
    @Autowired
    private TbDemoService demoService;
    
    // 获取数据列表
    @GetMapping("/list")
    public R list(TbDemo demo, PageQuery pageQuery) {
        PageInfo<TbDemo> pageInfo = demoService.selectDemoPage(demo, pageQuery);
        return R.ok().put("page", pageInfo);
    }
    
    // 根据ID获取详情
    @GetMapping("getById/{id}")
    public R getById(@PathVariable("id") Integer id) {
        TbDemo demo = demoService.getById(id);
        return R.ok().put("data", demo);
    }
    
    // 新增数据
    @PostMapping
    public R add(@RequestBody TbDemo demo) {
        demoService.save(demo);
        return R.ok();
    }
}

前端API调用

// src/api/demo.js
import request from '@/utils/request';

export function getDemoList(params) {
  return request({
    url: '/demo/list',
    method: 'get',
    params
  });
}

export function getDemoById(id) {
  return request({
    url: `/demo/getById/${id}`,
    method: 'get'
  });
}

export function addDemo(data) {
  return request({
    url: '/demo',
    method: 'post',
    data
  });
}

前端页面组件

<template>
  <div class="demo-container">
    <el-table v-loading="loading" :data="demoList">
      <el-table-column prop="id" label="ID" width="80" />
      <el-table-column prop="name" label="名称" />
      <el-table-column prop="age" label="年龄" width="80" />
      <el-table-column prop="createTime" label="创建时间" width="180" />
      <el-table-column label="操作" width="120">
        <template #default="scope">
          <el-button size="small" @click="handleEdit(scope.row)">编辑</el-button>
        </template>
      </el-table-column>
    </el-table>
    
    <el-pagination 
      :total="total" 
      v-model:page="pageNum" 
      v-model:page-size="pageSize"
      @current-change="handlePageChange"
    />
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import { getDemoList } from '@/api/demo';

const demoList = ref([]);
const total = ref(0);
const pageNum = ref(1);
const pageSize = ref(10);
const loading = ref(false);

const getList = async () => {
  loading.value = true;
  try {
    const res = await getDemoList({
      pageNum: pageNum.value,
      pageSize: pageSize.value
    });
    demoList.value = res.page.list;
    total.value = res.page.total;
  } finally {
    loading.value = false;
  }
};

const handlePageChange = (page) => {
  pageNum.value = page;
  getList();
};

onMounted(() => {
  getList();
});
</script>

3. 文件上传功能

后端文件上传控制器

@RestController
public class UploadController {
    @Autowired
    private UploadService uploadService;
    
    @PostMapping("upload")
    public R upload(@RequestParam("file") MultipartFile file) {
        String url = uploadService.uploadFile(file);
        return R.ok().put("url", url);
    }
}

文件上传工具类核心代码

public class FileUploadUtils {
    /**
     * 上传文件
     */
    public static String upload(MultipartFile file, String baseDir) throws IOException {
        // 获取文件扩展名
        String extension = FilenameUtils.getExtension(file.getOriginalFilename());
        // 生成唯一文件名
        String fileName = UUID.randomUUID().toString() + "." + extension;
        // 按日期创建目录
        String datePath = new SimpleDateFormat("yyyy/MM/dd").format(new Date());
        String filePath = baseDir + datePath + "/";
        
        File destFile = new File(filePath + fileName);
        // 确保目录存在
        if (!destFile.getParentFile().exists()) {
            destFile.getParentFile().mkdirs();
        }
        // 保存文件
        file.transferTo(destFile);
        
        // 返回访问URL
        return "/profile/" + datePath + "/" + fileName;
    }
}

环境搭建与部署指南

快速启动步骤

1. 环境准备

环境依赖 版本要求 验证命令
JDK 17+ java -version
Node.js 16+ node -v
MySQL 5.7+ mysql -V
Maven 3.6+ mvn -v

2. 项目获取与初始化

# 克隆项目代码
git clone https://gitcode.com/weixin_46699933/SpringBoot3-Vue3-Demo

# 进入项目目录
cd SpringBoot3-Vue3-Demo

3. 数据库配置

-- 创建数据库
CREATE DATABASE IF NOT EXISTS test CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 导入SQL文件
USE test;
SOURCE demo-admin/sql/test.sql;

4. 后端配置修改

# demo-admin/src/main/resources/application-dev.yml
spring:
  datasource:
    url: jdbc:mysql:///test?serverTimezone=GMT%2B8&userUnicode=true&characterEncoding=utf8
    username: 你的数据库用户名
    password: 你的数据库密码

5. 后端启动

# 进入后端目录
cd demo-admin

# 使用Maven启动
mvn spring-boot:run

6. 前端启动

# 进入前端目录(新开终端)
cd demo-vue

# 安装依赖
npm install

# 启动开发服务器
npm run dev

7. 访问应用

  • 后端API地址:http://localhost:8001
  • 前端页面地址:http://localhost:3000
  • 默认管理员账号:admin/admin123

多环境配置方案

后端多环境配置

# application.yml
spring:
  profiles:
    active: dev  # 激活开发环境配置
# application-dev.yml (开发环境)
server:
  port: 8001

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test
# application-prod.yml (生产环境)
server:
  port: 80

spring:
  datasource:
    url: jdbc:mysql://prod-mysql:3306/prod_db

启动命令

# 开发环境(默认)
mvn spring-boot:run

# 生产环境
mvn spring-boot:run -Dspring-boot.run.profiles=prod

前端环境配置

# .env.development
VITE_API_BASE_URL=http://localhost:8001

# .env.production
VITE_API_BASE_URL=https://api.yourdomain.com

性能优化与扩展建议

1. 后端性能优化

  1. 缓存策略

    @Configuration
    @EnableCaching
    public class CacheConfig {
        @Bean
        public CacheManager cacheManager() {
            CaffeineCacheManager cacheManager = new CaffeineCacheManager();
            // 设置缓存过期时间
            cacheManager.setCaffeine(Caffeine.newBuilder()
                    .expireAfterWrite(10, TimeUnit.MINUTES)
                    .maximumSize(1000));
            return cacheManager;
        }
    }
    
  2. 接口限流实现

    @Component
    public class RateLimiterInterceptor implements HandlerInterceptor {
        private final RateLimiter rateLimiter = RateLimiter.create(100.0); // 限制每秒100个请求
        
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            if (!rateLimiter.tryAcquire()) {
                response.setStatus(429);
                response.getWriter().write("请求过于频繁,请稍后再试");
                return false;
            }
            return true;
        }
    }
    

2. 前端性能优化

  1. 路由懒加载

    // src/router/index.js
    const routes = [
      {
        path: '/demo',
        name: 'Demo',
        component: () => import('@/views/sys/demo.vue') // 懒加载
      }
    ];
    
  2. 组件按需引入

    // 只引入需要的组件,减少打包体积
    import { ElButton, ElTable, ElPagination } from 'element-plus';
    

项目目录结构详解

SpringBoot3-Vue3-Demo/
├── demo-admin/           # 后端项目
│   ├── src/main/java/cn/itzd/
│   │   ├── controller/   # 控制器层
│   │   ├── service/      # 服务层
│   │   ├── mapper/       # 数据访问层
│   │   ├── entity/       # 实体类
│   │   ├── config/       # 配置类
│   │   └── utils/        # 工具类
│   ├── src/main/resources/
│   │   ├── application.yml       # 主配置文件
│   │   ├── application-dev.yml   # 开发环境配置
│   │   └── application-prod.yml  # 生产环境配置
│   └── sql/              # 数据库脚本
└── demo-vue/             # 前端项目
    ├── src/
    │   ├── api/          # API接口定义
    │   ├── components/   # 公共组件
    │   ├── views/        # 页面视图
    │   ├── router/       # 路由配置
    │   ├── utils/        # 工具函数
    │   └── assets/       # 静态资源
    ├── package.json      # 项目依赖
    └── vite.config.js    # Vite配置

常见问题解决方案

1. 跨域问题

问题表现:前端请求后端接口时控制台出现类似错误:

Access to XMLHttpRequest at 'http://localhost:8001/api' from origin 'http://localhost:3000' has been blocked by CORS policy.

解决方案

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOriginPatterns("*")
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(3600);
    }
}

2. JWT令牌过期

解决方案:前端实现令牌过期自动刷新机制

// 响应拦截器中添加token刷新逻辑
instance.interceptors.response.use(response => {
    return response;
}, async error => {
    const originalRequest = error.config;
    
    // 如果是401错误且未尝试刷新token
    if (error.response.status === 401 && !originalRequest._retry) {
        originalRequest._retry = true;
        try {
            // 调用刷新token接口
            const res = await refreshToken();
            localStorage.setItem('token', res.token);
            // 重新设置Authorization头
            originalRequest.headers['Authorization'] = res.token;
            // 重试原始请求
            return instance(originalRequest);
        } catch (err) {
            // 刷新token失败,需要重新登录
            localStorage.removeItem('token');
            router.push('/login');
            return Promise.reject(err);
        }
    }
    
    return Promise.reject(error);
});

总结与展望

SpringBoot3-Vue3-Demo作为一个全栈开发脚手架,提供了企业级应用开发所需的核心功能模块和最佳实践。通过本指南的学习,你已经掌握了:

  1. 基于Spring Boot 3和Vue 3的现代化全栈架构搭建方法
  2. 用户认证、权限管理、数据CRUD、文件上传等核心功能的实现原理
  3. 多环境配置与项目部署的完整流程
  4. 性能优化与常见问题的解决方案

未来扩展方向

  • 集成Redis实现分布式缓存
  • 添加消息队列实现异步处理
  • 引入微服务架构实现系统解耦
  • 集成ELK栈实现日志收集与分析

如果你觉得这个项目对你有帮助,请点赞、收藏并关注作者,获取更多技术干货!下期我们将带来"基于该脚手架开发企业级CMS系统"的实战教程,敬请期待!

附录:核心依赖版本清单

依赖名称 版本号
Spring Boot 3.0.5
MyBatis-Plus 3.5.3.1
JWT 0.11.5
MySQL Connector 8.0.32
Vue 3.3.8
Element Plus 2.4.1
Vite 5.1.0
Axios 1.3.4
登录后查看全文
热门项目推荐
相关项目推荐