You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TomEE服务器上Spring Boot Maven项目的React路由失效问题

问题描述

在TomEE服务器上部署整合React应用的Spring Boot Maven项目时,本地运行时React路由与Spring后端均正常,但部署到服务器后仅根路径(/)可正常访问,其他React路由(如/test)均返回Spring的404错误,服务器日志无报错信息。

相关代码

Spring控制器类

@CrossOrigin
@RestController
@RequestMapping("api")
public class DemoController {
    @GetMapping("/demo")
    public List<String> demo(){
        List<String> list = new ArrayList<>(Arrays.asList("Hello", "World", "from", "Spring!"));

        return list;
    }
}

React App.js

import {Route, Routes} from "react-router-dom";
import Test from "./components/test";

function App() {
  return (
      <Routes>
          <Route index element={<Test />} />
          <Route path="test" element={<div>Test</div>} />
      </Routes>
  );
}
export default App;

React index.js

...
import {BrowserRouter} from "react-router-dom";

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
      <BrowserRouter basename={process.env.PUBLIC_URL}>
          <App />
      </BrowserRouter>
  </React.StrictMode>
);

环境配置

  • .env.local
    PUBLIC_URL=.
    
  • .env.production
    PUBLIC_URL=/Expo-project-0.0.1-SNAPSHOT
    

package.json 脚本

"scripts": {
    "start": "react-scripts start",
    "build": "env-cmd -f ./.env.production react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  }

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.9</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>no.hvl.dat109</groupId>
    <artifactId>Expo-project</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>Expo-prosject</name>
    <description>Expo-prosject</description>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

已尝试的解决方法

  • 在.env文件中添加尾部斜杠
  • 使用HashRouter替代BrowserRouter
  • 修改控制器指向index.html

解决方案

问题核心是:直接访问React路由时,TomEE会将请求转发给Spring处理,但Spring没有对应路径的控制器,因此返回404。需要让Spring将所有非API的GET请求转发到index.html,由React路由接管处理。

1. 添加前端路由转发控制器

创建控制器,匹配所有非API、非静态资源的GET请求,转发到index.html:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class ForwardController {

    // 匹配所有不含后缀的路径,排除API和静态资源
    @GetMapping(value = "/**/{[path:[^\\.]*}")
    public String forwardToIndex() {
        return "forward:/index.html";
    }
}

2. 配置Maven复制React构建产物

修改pom.xml,添加资源复制插件,将React build后的文件自动复制到Spring的静态资源目录:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
        <!-- 复制React构建产物到Spring静态目录 -->
        <plugin>
            <artifactId>maven-resources-plugin</artifactId>
            <executions>
                <execution>
                    <id>copy-react-build</id>
                    <phase>process-resources</phase>
                    <goals>
                        <goal>copy-resources</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>${project.build.outputDirectory}/static</outputDirectory>
                        <resources>
                            <resource>
                                <directory>${project.basedir}/build</directory>
                                <filtering>false</filtering>
                            </resource>
                        </resources>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

执行顺序:先运行npm run build生成React构建产物,再执行mvn package打包war包。

3. 验证上下文路径配置

确保.env.production中的PUBLIC_URL与TomEE部署的war包上下文路径完全一致:

PUBLIC_URL=/Expo-project-0.0.1-SNAPSHOT

如果自定义了TomEE的上下文路径(如在conf/server.xml中配置Context的path属性),需同步修改PUBLIC_URL的值。

4. 确认TomEE部署

将打包好的war包放入TomEE的webapps目录,TomEE会自动解压部署。若需自定义上下文路径,可在conf/server.xml中添加:

<Context docBase="Expo-project-0.0.1-SNAPSHOT" path="/your-custom-path" reloadable="true"/>

内容的提问来源于stack exchange,提问作者Espen Grebstad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 09:57:03