SpringBoot整合Vue静态资源:一键打包部署实战指南
1. 为什么要把SpringBoot和Vue“合体”很多刚开始做全栈开发的朋友可能都经历过和我一样的痛苦。开发的时候前端用Vue在localhost:8080跑得飞快热更新爽得不行后端用SpringBoot在localhost:8081提供API调试接口也很方便。前后端分离各司其职感觉世界很美好。但一到要部署上线麻烦就来了。你得先找个Nginx服务器把前端打包好的dist文件夹放上去配置好监听端口和静态资源路径。然后再把SpringBoot项目打成JAR包扔到服务器上运行。这还没完因为前端页面和后端API不在同一个域名和端口下浏览器会抛出那个令人头疼的“跨域”错误。于是你又得回头去折腾Nginx的反向代理配置或者给SpringBoot加上一堆CrossOrigin注解。整个过程就像在玩一个复杂的拼图游戏任何一个环节配错页面就白屏接口就404。我当初跟着导师做项目就在这个环节卡了好几天请教了学长才勉强部署成功。结果导师一句话点醒了我“咱们这项目也不大团队就这几个人部署搞得这么复杂前后端分离的优势好像没体现出来啊能不能想想办法让它部署起来像传统项目一样简单”这句话让我开始思考。前后端分离在开发阶段的优势是毋庸置疑的但部署的复杂度确实是个门槛。对于中小型项目或者快速交付的场景我们能不能“鱼与熊掌兼得”答案是肯定的。“开发分离部署合一”就成了一个非常理想的方案。具体来说就是在开发时Vue和SpringBoot各自独立运行享受分离带来的高效而在部署时将Vue编译好的静态文件HTML、CSS、JS、图片等直接嵌入到SpringBoot项目中最终打成一个可执行的、独立的JAR包。这样一来部署时只需要运行这一个JAR前端页面和后端服务天然就在同一个源Origin下跨域问题烟消云散运维成本直线下降。这种模式特别适合个人开发者、创业小团队或者需要快速交付内部工具的场景。你不需要额外维护一个Web服务器如Nginx的配置项目自包含迁移和分发都极其方便。接下来我就手把手带你走一遍这个“合体”的全过程把我踩过的坑和总结的经验都分享给你。2. 前期准备理清你的项目结构在开始动手之前我们得先明确两个项目的状态和位置。假设你已经有了一个可以正常运行的Vue项目和一个SpringBoot项目。为了清晰起见我建议你按以下目录结构来组织这会让你后续的操作思路非常清晰。你的工作空间/ ├── vue-project/ # 你的Vue前端项目 │ ├── public/ │ ├── src/ │ ├── vue.config.js │ └── package.json └── springboot-project/ # 你的SpringBoot后端项目 ├── src/ │ └── main/ │ ├── java/ # 你的Java代码 │ └── resources/ │ ├── static/ # 等下前端文件就放这里 │ ├── templates/ │ └── application.properties └── pom.xml关键点一Vue项目的路由模式。这是第一个容易踩坑的地方。Vue-Router有两种模式hash模式和history模式。Hash模式URL中会带有一个#例如http://localhost:8080/#/home。这种模式的好处是即使部署到静态服务器也不需要服务器端做任何特殊配置因为#后面的内容不会被发送到服务器。兼容性最好。History模式URL是干净的如http://localhost:8080/home。体验更好但需要服务器端支持确保所有前端路由的请求都返回index.html否则刷新页面会404。在我们这种“合体”部署方案里我强烈建议新手先使用Hash模式可以避免很多不必要的配置麻烦。如果你的项目已经是History模式也不用慌我们后面在SpringBoot配置里会有对应的解决办法。关键点二SpringBoot的静态资源路径。SpringBoot默认会在几个地方寻找静态资源其中classpath:/static/是最常用的。我们的目标就是把Vue打包后的所有文件完整地复制到这个目录下。这样SpringBoot启动后就能像提供自己的静态文件一样提供前端页面了。3. 第一步搞定Vue的打包配置很多教程一上来就让你改vue.config.js里的publicPath把它改成./相对路径。这个操作的本意是让打包后的静态资源引用路径使用相对路径避免在子路径下部署时出现资源加载失败。但我实测下来这步操作并不是必须的而且有时会引入新问题。就像我原始经历里写的我因为盲目跟随教程改了这里导致后端怎么也访问不到静态资源排查了很久。其实在我们将静态资源放入SpringBoot的/static/目录下并且通过正确的资源配置后使用默认的publicPath通常是/是完全可行的。所以对于大多数项目我建议你先保持vue.config.js的简洁只保留开发时的代理配置即可生产打包配置可以暂时不动。下面是一个典型的、用于开发的配置示例// vue.config.js const { defineConfig } require(vue/cli-service) module.exports defineConfig({ transpileDependencies: true, devServer: { port: 8080, // 前端开发服务器端口 proxy: { // 代理所有以 /api 开头的请求到后端 /api: { target: http://localhost:8081, // 你的SpringBoot后端地址 changeOrigin: true, // 通常不需要重写路径除非后端接口路径本身不带 /api // pathRewrite: { ^/api: } } } } })配置好后在Vue项目根目录下运行打包命令npm run build或者如果你用的是yarnyarn build命令执行成功后会在项目根目录下生成一个dist文件夹。打开它你会看到类似这样的结构dist/ ├── css/ │ └── app.xxxxxx.css ├── js/ │ ├── app.xxxxxx.js │ └── chunk-vendors.xxxxxx.js ├── favicon.ico └── index.html这个dist文件夹里的所有东西就是我们前端的全部“家当”。接下来我们要把它们搬个家。4. 第二步将前端资源整合进SpringBoot这一步是物理上的整合非常简单就是复制粘贴。在你的SpringBoot项目中找到src/main/resources/目录。如果里面没有static文件夹就新建一个。将Vue项目dist文件夹下的所有文件和文件夹注意是dist里面的内容不是dist文件夹本身全部复制到src/main/resources/static/目录下。完成后你的SpringBoot资源目录应该看起来像这样springboot-project/src/main/resources/ └── static/ ├── css/ ├── js/ ├── favicon.ico └── index.html这里有一个非常重要的细节需要检查用文本编辑器打开复制过来的index.html。查看里面对于CSS和JS文件的引用路径比如link href/css/app.xxxxxx.css和script src/js/app.xxxxxx.js。你会发现它们都是以斜杠/开头的绝对路径。这意味着浏览器会向当前服务器的根路径去请求这些资源例如http://localhost:8081/css/app.xxxxxx.css。这正是我们想要的因为接下来我们就要配置SpringBoot让它正确处理对/static/目录下资源的请求并将其映射到服务器的根路径。5. 第三步配置SpringBoot的静态资源映射这是整个流程的核心技术环节。我们需要告诉SpringBoot两件事第一静态资源放在哪里第二如何对外提供这些资源。这里我提供两种主流配置方式推荐使用第二种更现代、更清晰。5.1 方式一使用WebMvcConfigurer推荐这是SpringBoot 2.x之后更推荐的方式通过实现WebMvcConfigurer接口来添加自定义配置。import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; Configuration public class WebConfig implements WebMvcConfigurer { Override public void addResourceHandlers(ResourceHandlerRegistry registry) { // 关键配置将所有访问路径映射到 classpath:/static/ 目录 registry.addResourceHandler(/**) .addResourceLocations(classpath:/static/); // 如果你使用了Swagger等文档工具可能需要额外添加其资源路径 // registry.addResourceHandler(/webjars/**) // .addResourceLocations(classpath:/META-INF/resources/webjars/); } }这段配置的意思是当有请求进来比如/css/app.css或/js/app.jsSpringBoot会去classpath:/static/目录下寻找对应的文件。/**是一个通配符匹配所有路径。5.2 方式二在application.properties或application.yml中配置你也可以通过配置文件来指定静态资源的路径这种方式更简洁。application.properties 配置# 设置静态资源的请求路径模式默认就是 /** spring.mvc.static-path-pattern/** # 设置静态资源的位置多个位置用逗号分隔 spring.web.resources.static-locationsclasspath:/static/application.yml 配置spring: mvc: static-path-pattern: /** web: resources: static-locations: classpath:/static/这两种方式Java配置和文件配置在功能上是等价的选择一种即可。我个人更喜欢用Java配置类因为逻辑更集中也方便以后添加更复杂的规则。5.3 处理Vue Router的History模式如果你的Vue项目使用的是History模式那么当用户直接访问一个深层次路由如/home/user或刷新页面时SpringBoot会把这个路径当作一个真实的API请求去处理显然找不到对应的处理器从而返回404。为了解决这个问题我们需要添加一个“回退”规则当请求的资源不存在时统一返回index.html让Vue前端自己去处理路由。在刚才的WebConfig配置类中增加一个方法import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; Configuration public class WebConfig implements WebMvcConfigurer { Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/**) .addResourceLocations(classpath:/static/); } // 专门用于处理History模式的配置 Override public void addViewControllers(ViewControllerRegistry registry) { // 匹配所有未映射到其他处理器的前端路由请求转发到 index.html registry.addViewController(/{path:[^\\.]*}) .setViewName(forward:/index.html); } }这个/{path:[^\\.]*}是一个正则表达式意思是匹配所有不包含点号.的路径。因为像/css/app.css这样的静态资源请求是包含点号的它们会被上面的addResourceHandlers处理。而不包含点号的路径如/home、/about就会被转发到index.html。6. 第四步处理安全框架如Spring Security的放行如果你的项目像我一样使用了Spring Security来做权限控制那么默认情况下它会拦截所有请求包括静态资源。如果不做配置你会发现浏览器能请求到index.html但页面里的CSS、JS、图片全都加载不了控制台报403错误。我们需要在Spring Security的配置中明确告诉它哪些静态资源路径不需要认证。import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { Override public void configure(WebSecurity web) throws Exception { // 忽略对静态资源的认证拦截 web.ignoring().antMatchers( /css/**, /js/**, /img/**, /fonts/**, /favicon.ico, /index.html // 如果直接访问首页也不需要认证的话 ); } Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers(/api/admin/**).hasRole(ADMIN) // 你的API权限规则 .antMatchers(/api/user/**).hasRole(USER) .anyRequest().authenticated() // 其他所有请求都需要认证 .and() .formLogin() .loginPage(/login) // 如果你的登录页也是Vue页面这里要对应 .permitAll() .and() .logout() .permitAll(); // ... 其他csrf、session等配置 } }注意web.ignoring()和http.authorizeRequests()的区别。ignoring()是完全绕过安全过滤器链性能最好适合纯静态资源。而如果某些页面如/login你希望它被安全链处理比如记录日志但又不需要认证则应该在http.authorizeRequests()中使用.permitAll()。7. 第五步打包、测试与一键部署经过以上配置整合工作就基本完成了。现在我们来验证成果。打包SpringBoot项目在SpringBoot项目根目录下使用Maven命令打包mvn clean package如果使用Gradle则是./gradlew clean build打包成功后在target目录Gradle在build/libs下你会找到生成的your-project-0.0.1-SNAPSHOT.jar文件。这个JAR包已经包含了编译好的后端代码和前端所有的静态资源。本地测试运行在命令行中运行这个JAR包java -jar target/your-project-0.0.1-SNAPSHOT.jar应用启动后打开浏览器访问http://localhost:8080假设你的服务器端口是8080。你应该能直接看到Vue应用的首页。尝试点击页面内的路由跳转刷新页面一切都应该正常工作。再打开开发者工具的网络面板查看CSS、JS等资源的加载应该都是成功的200状态码并且来自同一个localhost:8080源没有任何跨域错误。部署到服务器部署变得异常简单。只需要将这一个JAR包上传到你的Linux或Windows服务器然后用同样的java -jar命令运行即可。你可以使用nohup或 systemd 等服务管理工具让它后台运行。# 简单后台运行示例 nohup java -jar your-project-0.0.1-SNAPSHOT.jar app.log 21 关于“隐藏index.html”你可能会觉得浏览器地址栏里的/index.html#/不够优雅。想直接通过http://localhost:8080/访问。这通常需要在SpringBoot中设置一个默认的首页。在WebConfig中再添加一条规则即可Override public void addViewControllers(ViewControllerRegistry registry) { // 将根路径 / 重定向到 /index.html registry.addRedirectViewController(/, /index.html); // 保留History模式的回退规则 registry.addViewController(/{path:[^\\.]*}) .setViewName(forward:/index.html); }这样访问http://localhost:8080/就会自动跳转到前端应用了。整个流程走下来你会发现“开发分离部署合一”的模式完美兼顾了开发效率和部署简便性。开发时前后端并行不悖部署时一个命令一个文件开箱即用。对于追求快速迭代和简化运维的中小项目来说这无疑是一个非常值得掌握的实用技巧。我在多个内部管理系统中都采用了这种方式再也没有被部署和跨域问题困扰过。

相关新闻

【eclipse】快速切换中英文界面:一键汉化与还原技巧

【eclipse】快速切换中英文界面:一键汉化与还原技巧

1. 为什么你需要快速切换Eclipse的界面语言? 我猜很多朋友刚开始用Eclipse的时候,都跟我当年一样,看着满屏的英文菜单和按钮,心里有点发怵。尤其是刚入门编程,或者从其他中文界面的IDE转过来,总觉得哪里不对…

2026/7/5 9:15:59 阅读更多 →
【存算一体开发生死线】:为什么你的C封装在28nm工艺下时序崩溃?3类未声明依赖的硬核修复方案

【存算一体开发生死线】:为什么你的C封装在28nm工艺下时序崩溃?3类未声明依赖的硬核修复方案

第一章:存算一体芯片 C 语言指令集封装存算一体(Computing-in-Memory, CIM)架构通过在存储阵列中嵌入计算单元,显著降低数据搬运开销。为提升开发者友好性,硬件厂商通常提供一套轻量级 C 语言接口层,将底层…

2026/7/4 19:35:09 阅读更多 →
SmolVLA赋能.NET开发:C#集成与智能业务逻辑构建

SmolVLA赋能.NET开发:C#集成与智能业务逻辑构建

SmolVLA赋能.NET开发:C#集成与智能业务逻辑构建 最近在做一个企业内部的文档处理系统,客户提了个需求,说能不能让系统“聪明”一点,比如自动看看合同里有没有风险条款,或者把一堆数据自动整理成报告。这让我想起了之前…

2026/7/3 2:13:35 阅读更多 →

最新新闻

MATLAB图形化图像水印工具:支持DCT/DWT嵌入提取与攻击测试

MATLAB图形化图像水印工具:支持DCT/DWT嵌入提取与攻击测试

本文还有配套的精品资源,点击获取 简介:一套开箱即用的MATLAB图像水印实验工具,带可视化操作界面(shuiyin.fig),支持离散余弦变换(DCT)和离散小波变换(DWT&#xff09…

2026/7/5 9:14:35 阅读更多 →
跨架构物联网漏洞挖掘:统一IR与动静结合分析实践

跨架构物联网漏洞挖掘:统一IR与动静结合分析实践

1. 项目概述:为什么我们需要“跨架构”的物联网漏洞挖掘?干了这么多年安全,尤其是物联网这块,我最大的感受就是“乱”。你面对的从来不是单一平台,而是ARM、MIPS、x86、RISC-V,甚至各种魔改的MCU架构大杂烩…

2026/7/5 9:12:35 阅读更多 →
热红外视觉下的车辆/船舶重识别新方法:Vc-fes

热红外视觉下的车辆/船舶重识别新方法:Vc-fes

在监控与海事安防等场景中,如何在**热红外图像**(灰度、无色彩、纹理弱)中准确识别同一辆车或同一艘船,是一个长期悬而未决的难题。近期发表于《International Journal of Machine Learning and Cybernetics》(2026年)的论文《Vc-fes: viewpoint-conditioned feature selection…

2026/7/5 9:10:34 阅读更多 →
本地AI完全指南①:我把ChatGPT退了,一年省2400——为什么越来越多人把大模型搬回家

本地AI完全指南①:我把ChatGPT退了,一年省2400——为什么越来越多人把大模型搬回家

title: 本地AI完全指南①:我把ChatGPT退了,一年省2400——为什么越来越多人把大模型搬回家? tags: 本地AI,私有大模型,Ollama,DeepSeek,大模型部署,AI隐私,离线AI,本地部署大模型,DeepSeek本地部署 category: 人工智能 本地AI完全指南①&…

2026/7/5 9:10:34 阅读更多 →
同一个模型,三个平台:OpenRouter - SiliconFlow - DeepInfra 实测对比

同一个模型,三个平台:OpenRouter - SiliconFlow - DeepInfra 实测对比

前面几期测的都是模型官方 API。但你实际用的时候,大概率走的不是官方——而是通过某个聚合平台。 为什么?几个现实原因: 不想每个模型绑一张信用卡公司采购要求统一结算官方 API 在某些地区不稳定想用一个 API Key 调所有模型 所以这期我不测…

2026/7/5 9:10:34 阅读更多 →
GRPO训练燃料:把Hermes Agent Feedback变成强化学习信号

GRPO训练燃料:把Hermes Agent Feedback变成强化学习信号

GRPO训练燃料:把Agent Feedback变成强化学习信号 「Hermes Agent自进化智能体深度解析」系列 | 模块十六 第3篇 你的Agent积累了1000条执行轨迹。500条成功,500条失败。成功的路径有的快、有的慢,失败的失败方式各不相同。你盯着这些数据&a…

2026/7/5 9:08:34 阅读更多 →

日新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

月新闻