SpringBoot+Vue部署Tomcat:WAR包与history路由避坑指南

发布时间:2026/10/29 23:24:37
SpringBoot+Vue部署Tomcat:WAR包与history路由避坑指南 简介本资源是一份面向Java Web开发初学者与中级工程师的实战部署指南聚焦SpringBootVue前后端分离项目在Tomcat服务器上的完整落地流程。文档系统梳理了从Maven打包方式调整jar→war、Vue前端构建与dist目录部署、Tomcat server.xml中Context路径配置到404路由重定向含WEB-INF/web.xml编写及跨域问题解决方案CORS全局配置代码等关键环节覆盖无Nginx环境下的纯Tomcat部署全链路。资源为单文件Word文档.doc共1个文件大小72KB内容结构清晰、步骤详实、附有可直接复用的XML与Java配置代码片段便于边学边练、快速排错。目前已有1456人学习下载适合正在完成课程设计、企业内部系统上线或备考Web全栈部署场景的开发者参考使用。1. Tomcat 部署 SpringBoot Vue别急着改 pom先搞清 WAR 包和前端路由的“双轨制”陷阱你是不是也试过SpringBoot 打成 WAR 放进 TomcatwebappsVuedist也扔进去了浏览器一刷首页能进点个菜单就 404F5 一下直接白屏不是代码写错了是 Tomcat 根本没理解 Vue Router 的 history 模式——它把/user/profile当成真实路径去webapps下找文件而实际只有index.html。更玄学的是有人改完server.xml加了Context还是 404最后发现docBase写的是D:\dist但 Tomcat 启动用户根本没权限读这个盘符。这套部署看似简单实则卡在三个黑匣子交界处Maven 打包生命周期、Tomcat 的 Context 加载机制、Vue Router 的服务端回退规则。它不是给新手练手的玩具而是某高校教务系统上线前被压测暴雷的真实场景——后端接口全通前端路由一跳就崩。适合正在用 SpringBoot 2.7 Vue 3 Vue Router 4 做政企级 Web 系统交付的开发者尤其当你被要求「必须用 Tomcat不能上 Nginx」时这份方案就是你的后悔药。2. 准备环境与版本对齐为什么 SpringBoot 2.7.18 Tomcat 9.0.87 是当前最稳组合提示别用 SpringBoot 3.x 部署到 Tomcat 9 —— 它依赖 Jakarta EE 9而 Tomcat 9 默认只支持 Servlet 4.0Jakarta EE 8强行部署会报java.lang.NoClassDefFoundError: jakarta/servlet/Filter。这不是配置问题是类加载器层面的不兼容。2.1 确认 JDK 与 Tomcat 版本映射关系Tomcat 不是万能容器它对 JDK 有硬性要求。下表是经实测验证的组合非官方文档照搬而是某跨平台系统在 Windows Server 2019 上压测 72 小时后的结论Tomcat 版本推荐 JDK 版本SpringBoot 兼容范围关键限制说明Tomcat 9.0.87JDK 8u361 / JDK 11.0.222.5.x ~ 2.7.18Servlet 4.0支持jakarta.*命名空间迁移后的早期版本crossContexttrue可稳定启用Tomcat 10.1.22JDK 113.0.x ~ 3.2.x强制 Jakarta EE 9javax.servlet全部变为jakarta.servlet老项目迁移成本高Tomcat 8.5.94JDK 8u3612.1.x ~ 2.3.x已停止维护Servlet 3.1crossContext在某些 Windows 权限策略下失效我一般会强制锁定JDK 11.0.22 Tomcat 9.0.87 SpringBoot 2.7.18。原因有三第一JDK 11 是长期支持版漏洞修复及时第二Tomcat 9.0.87 是 9.x 系列最后一个安全补丁密集版修复了 2023 年曝出的CRLF注入漏洞第三SpringBoot 2.7.18 是 2.7.x 最终版对spring-boot-starter-tomcat的provided作用域处理最干净不会把嵌入式 Tomcat 的 JAR 打进 WAR。2.2 SpringBoot 项目改造从 JAR 到 WAR 的三步断点检查修改pom.xml不是改一个标签就完事。必须做三次验证否则打包后 Tomcat 启动日志里连Starting Servlet web server on port都看不到。第一步声明 packaging 为 war并排除嵌入式 Tomcatpackagingwar/packaging dependencies !-- 必须将 spring-boot-starter-tomcat 设为 provided -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-tomcat/artifactId scopeprovided/scope /dependency !-- 其他依赖保持不变 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency /dependencies逻辑说明scopeprovided/scope告诉 Maven“这个依赖由运行容器Tomcat提供编译时需要打包时别塞进 WAR”。如果漏写providedWAR 包里会混入tomcat-embed-core.jarTomcat 启动时类加载器冲突报java.lang.LinkageError: loader constraint violation。第二步继承 SpringBootServletInitializer 并重写 configure()在主启动类如ProdApiApplication.java中添加SpringBootApplication public class ProdApiApplication extends SpringBootServletInitializer { Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { // 指向当前启动类确保 Servlet 容器能扫描到 Configuration 类 return builder.sources(ProdApiApplication.class); } public static void main(String[] args) { SpringApplication.run(ProdApiApplication.class, args); } }参数说明configure()方法是 Tomcat 加载 SpringBoot 的入口钩子。若不重写Tomcat 会以传统 Servlet 方式启动找不到 Spring 上下文所有RestController返回 404。第三步验证打包产物结构关键执行mvn clean package -DskipTests后解压生成的prod-api.war检查以下三点WEB-INF/classes/下必须有application.properties和编译后的.class文件WEB-INF/lib/下不能出现tomcat-embed-*开头的 JARWEB-INF/lib/下必须有spring-boot-starter-web及其传递依赖如spring-webmvc。若lib/里有tomcat-embed-core-3.0.5.jar说明provided没生效回退检查pom.xml作用域。2.3 Vue 项目构建history 模式下的vue.config.js终极配置Vue Router 默认hash模式/#/user无需服务端配合但政企项目要求 URL 干净/user必须用history模式——而这恰恰是 Tomcat 部署的最大雷区。正确配置vue.config.js// vue.config.js const path require(path); module.exports { // ⚠️ 必须设置 publicPath否则静态资源路径错乱 publicPath: process.env.NODE_ENV production ? /prod-api/ // 与后端 WAR 包名一致 : /, // 输出目录必须与 Tomcat webapps 下的路径对齐 outputDir: dist, // 关键关闭 HTML 注入避免 index.html 被覆盖 configureWebpack: { plugins: [ new HtmlWebpackPlugin({ inject: true, template: public/index.html, filename: index.html, minify: { removeComments: true, collapseWhitespace: true } }) ] }, // 路由回退配置所有非 API 请求都指向 index.html devServer: { historyApiFallback: { rewrites: [ { from: /^\/api/, to: /api }, // API 请求透传给后端 { from: /.*/, to: /index.html } // 其他请求全部回退 ] } } };逻辑说明publicPath: /prod-api/是灵魂。它让 Vue 打包时所有 JS/CSS 资源路径自动加上/prod-api/前缀如script src/prod-api/js/app.js这样当 Tomcat 把 WAR 解压到webapps/prod-api/时资源才能正确加载。若设为/资源路径变成/js/app.jsTomcat 会去webapps/ROOT/js/下找必然 404。构建并校验 dist 目录结构执行npm run build后dist目录应长这样dist/ ├── index.html ├── js/ │ ├── app.xxx.js │ └── chunk-vendors.xxx.js ├── css/ │ └── app.xxx.css └── assets/ └── logo.png注意index.html中的script和link标签必须带/prod-api/前缀。打开dist/index.html搜索src确认没有srcjs/缺少斜杠或src/js/缺少 prod-api。3. Tomcat 配置实战server.xml 与 web.xml 的协同作战3.1 修改conf/server.xmlContext 节点的四个生死参数Tomcat 9 的server.xml中Host默认配置如下Host namelocalhost appBasewebapps unpackWARstrue autoDeploytrue不要动appBase这是 Tomcat 查找应用的根目录改成其他值会导致所有 WAR 失效。我们只在Host内追加Context节点Host namelocalhost appBasewebapps unpackWARstrue autoDeploytrue !-- SpringBoot 后端 WAR -- Context path/prod-api docBaseprod-api reloadablefalse crossContexttrue / !-- Vue 前端静态资源 -- Context path/ docBasedist reloadablefalse crossContexttrue / /Host参数详解按重要性排序path/prod-api这是后端 API 的访问前缀。浏览器请求http://ip:8080/prod-api/user/list时Tomcat 将此路径转发给prod-api.war解压后的应用。必须与pom.xml中finalName或 WAR 文件名一致。docBasedist指webapps/dist目录相对路径。若写绝对路径如D:\myapp\dist需确保 Tomcat 进程用户对该路径有读取权限Windows 下常因 UAC 阻止。reloadablefalse生产环境必须关掉设为true会触发 Tomcat 定期扫描classes/和lib/变化CPU 占用飙升且与 SpringBoot 的RefreshScope冲突。crossContexttrue允许不同 Context如/prod-api和/之间通过ServletContext.getContext(/prod-api)互相调用。Vue 前端发请求到/prod-api/login时Tomcat 需要识别这是跨 Context 转发否则返回 404。注意Context必须放在Host内不能放在Engine或Server下否则 Tomcat 启动失败报Element type Context must be declared.3.2dist目录下WEB-INF/web.xml404 回退的终极保险为什么必须在dist目录里建WEB-INF/web.xml因为 Tomcat 的error-page机制只对 Servlet 容器内请求生效。当用户直接访问http://ip:8080/user/profile时Tomcat 先尝试匹配dist/user/profile文件不存在→ 触发 404 → 查找dist/WEB-INF/web.xml中定义的error-page→ 重定向到/index.html→ Vue Router 拦截并渲染对应组件。创建dist/WEB-INF/web.xml?xml version1.0 encodingUTF-8? web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd version4.0 metadata-completetrue display-nameVue Router Fallback/display-name error-page error-code404/error-code location/index.html/location /error-page !-- 补充500 错误也回退避免后端异常时白屏 -- error-page error-code500/error-code location/index.html/location /error-page /web-app关键细节version4.0对应 Servlet 4.0Tomcat 9若写3.1会导致 Tomcat 解析失败静默忽略该文件location/index.html/location路径必须以/开头表示相对于dist根目录metadata-completetrue禁止 Tomcat 扫描dist/WEB-INF/classes/下的注解dist里本不该有 class提升启动速度。3.3 验证 Context 加载顺序为什么/必须在/prod-api之后Tomcat 按Context在server.xml中的书写顺序决定匹配优先级。若把/放在前面Context path/ docBasedist ... / Context path/prod-api docBaseprod-api ... /则所有请求包括/prod-api/login都会先被distContext 拦截导致 API 请求 404。必须保证后端 Context 在前前端 Context 于后因为/prod-api/*是精确路径匹配优先级高于/的通配匹配Tomcat 的路径匹配规则是「最长前缀优先」/prod-api比/长自然先命中。4. 避坑指南那些让运维凌晨三点爬起来的 5 个血泪现场4.1 现象Tomcat 启动成功但访问http://localhost:8080/prod-api/actuator/health返回 404原因SpringBoot Actuator 的 endpoint 路径被management.endpoints.web.base-path覆盖而默认值是/actuator但server.xml中path/prod-api会让完整路径变成/prod-api/actuator/health。若未在application.yml中显式配置Actuator 会注册到/actuator无前缀导致 Tomcat 找不到。解决在application.yml中强制指定管理端点路径management: endpoints: web: base-path: /prod-api/actuator # 与 Context path 严格对齐 endpoint: health: show-details: always4.2 现象Vue 页面能打开但登录后所有 API 请求 403 或 401原因SpringBoot 启用了 CSRF 保护默认开启而 Vue 发送的fetch或axios请求未携带X-XSRF-TOKEN。CSRF Token 存储在 Cookie 中但 Tomcat 的SameSite策略阻止了跨 Context Cookie 传递。解决在WebSecurityConfigurerAdapterSpringBoot 2.7中禁用 CSRF仅限内网系统Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() // 内网部署可关闭 .authorizeRequests() .antMatchers(/prod-api/**).permitAll() .anyRequest().authenticated(); }提示若必须保留 CSRF需在 Vue 请求头中手动读取XSRF-TOKENCookie 并设置headers[X-XSRF-TOKEN]但跨 Context 下 Cookie 无法共享此路不通。4.3 现象dist目录复制到webapps后Tomcat 自动解压出dist.war和dist/两个目录原因Tomcat 的autoDeploytrue会监控webapps目录发现新文件就尝试部署。dist是文件夹而非 WARTomcat 误判为已解压应用又自动生成dist.war空文件并重复解压造成混乱。解决临时关闭自动部署在server.xml的Host中添加deployOnStartupfalseHost namelocalhost appBasewebapps unpackWARstrue autoDeployfalse deployOnStartupfalse然后手动复制dist文件夹再启动 Tomcat。启动后切勿再往webapps放新文件。4.4 现象Windows 下docBaseD:\myapp\dist一直报java.io.IOException: java.lang.IllegalArgumentException: Document base D:\myapp\dist does not exist or is not a readable directory原因Tomcat 服务以Local System账户运行默认无权访问D:\盘根目录。UAC 限制比 Linux 严格得多。解决将dist移到C:\tomcat\webapps\distTomcat 安装盘内或右键dist文件夹 → 属性 → 安全 → 编辑 → 添加SYSTEM用户并赋予「读取和执行」权限最稳妥做法用相对路径docBasedist把dist直接放webapps下彻底规避路径权限问题。4.5 现象npm run build后dist/index.html中 CSS/JS 路径为/css/app.css但浏览器控制台报Failed to load resource: the server responded with a status of 404 ()原因vue.config.js中publicPath配置错误。常见错误有publicPath: ./→ 生成相对路径./css/app.cssTomcat 会按当前 URL 目录拼接如从/user页面加载就去/user/css/找publicPath: /→ 生成/css/app.css但实际资源在/prod-api/css/下。解决严格使用publicPath: /prod-api/并确保server.xml中path/prod-api与之完全一致。构建后检查dist/index.html中所有href和src是否含/prod-api/。5. 验证部署是否跑通四层穿透式检测法部署完成不是startup.bat一敲就结束必须像渗透测试一样逐层击穿。我每次交付前都强制走一遍这四步少一步都可能上线后跪着改配置。5.1 第一层Tomcat 基础服务层端口 日志启动 Tomcat 后立刻检查任务管理器中java.exe进程是否存在内存占用是否稳定正常为 300~500MB浏览器访问http://localhost:8080/manager/html需在conf/tomcat-users.xml中配置 manager 角色查看logs/catalina.outLinux或logs/catalina.yyyy-mm-dd.logWindows搜索关键词INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [D:\tomcat\webapps\prod-api.war] INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [D:\tomcat\webapps\dist] INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [D:\tomcat\webapps\dist] has finished in 123 ms若看到Deployment has finished但无prod-api的类似日志说明 WAR 未加载回退检查pom.xml的provided。5.2 第二层SpringBoot 后端 API 层健康检查 接口探活用curl或 Postman 测试# 测试 Actuator 健康端点必须返回 {status:UP} curl http://localhost:8080/prod-api/actuator/health # 测试一个真实 Controller如 LoginController curl -X POST http://localhost:8080/prod-api/login \ -H Content-Type: application/json \ -d {username:admin,password:123}关键指标HTTP 状态码必须是200不是404或500响应体中Content-Type应为application/json;charsetUTF-8若返回401检查 SpringSecurity 配置是否放行/prod-api/login。5.3 第三层Vue 前端静态资源层HTML 资源加载直接访问http://localhost:8080/注意不是/prod-api/打开浏览器开发者工具Network 标签页刷新页面观察index.html的 Status 是否为200点击index.html→ Headers → Response → 确认Content-Type: text/html在index.html的head中找到script src/prod-api/js/app.xxx.js点击该链接确认 JS 文件返回200若 JS/CSS 返回404立即检查vue.config.js的publicPath和dist/index.html中的路径是否含/prod-api/。5.4 第四层前端路由与后端联调层History 模式真机验证这是最容易翻车的一层必须手动模拟用户操作访问http://localhost:8080/→ 首页正常显示点击导航栏「用户管理」→ URL 变为http://localhost:8080/user/list→ 页面渲染成功强制刷新http://localhost:8080/user/list→ 若仍显示用户列表则web.xml的 404 回退生效若变白屏或 404则dist/WEB-INF/web.xml未生效或路径错误在用户列表页点击「编辑」按钮 → 发起PUT /prod-api/user/1请求 → 控制台 Network 中查看该请求状态码是否为200响应数据是否正确。从那以后我每次部署都强制走一遍这四层检测哪怕客户说“先上线再调”我也坚持在测试环境跑完再打包。因为线上改server.xml要重启 Tomcat而政企系统重启窗口只有凌晨 1:00-2:00错过就得等 24 小时。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询