部署在Railway.app的Java Spring MVC应用崩溃或无法访问控制器路径
Spring MVC应用本地Tomcat运行正常,部署到Railway.app后崩溃无响应
问题说明
我开发的Java Spring MVC Web应用在本地Tomcat环境运行正常,但部署到Railway.app平台后直接崩溃,访问任何控制器路径都没有响应。以下是项目核心配置与代码:
pom.xml
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>pl.krzysztofskul</groupId> <artifactId>sensit5</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>sensit5</name> <description>A simple sensit5.</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <failOnMissingWebXml>false</failOnMissingWebXml> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <java.version>8</java.version> <maven-compiler-pluging.version>3.10.1</maven-compiler-pluging.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.5.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/javax.servlet/jstl --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> <scope>runtime</scope> </dependency> <!-- E-MAIL --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>5.2.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <!-- <version>5.1.8.RELEASE</version>--> <version>5.2.5.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-jpa --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>2.1.9.RELEASE</version> </dependency> </dependencies> <build> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <plugin> <artifactId>maven-site-plugin</artifactId> <version>3.7.1</version> </plugin> <plugin> <artifactId>maven-project-info-reports-plugin</artifactId> <version>3.0.0</version> </plugin> <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging --> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>${maven-compiler-pluging.version}</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.3.2</version> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.1</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.1.0</version> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> <mainClass>pl.krzysztofskul.sensit5.App</mainClass> </manifest> </archive> </configuration> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.5.2</version> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.8.2</version> </plugin> </plugins> </pluginManagement> </build> <reporting> <plugins> <plugin> <artifactId>maven-project-info-reports-plugin</artifactId> </plugin> </plugins> </reporting> </project>
App.java
package pl.krzysztofskul.sensit5; import javax.servlet.Filter; import org.springframework.web.filter.CharacterEncodingFilter; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class App extends AbstractAnnotationConfigDispatcherServletInitializer { public static void main( String[] args ) { System.out.println( "Hello World sensit5!" ); } @Override protected Class<?>[] getRootConfigClasses() { return null; } @Override protected Class<?>[] getServletConfigClasses() { return new Class[]{AppConfig.class}; } @Override protected String[] getServletMappings() { return new String[]{"/"}; } @Override protected Filter[] getServletFilters() { CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); characterEncodingFilter.setEncoding("UTF-8"); return new Filter[] { characterEncodingFilter }; } }
AppConfig.java
package pl.krzysztofskul.sensit5; import java.util.Locale; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.LocaleContextResolver; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.i18n.SessionLocaleResolver; import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.JstlView; @Configuration @EnableWebMvc @ComponentScan(basePackages = "pl.krzysztofskul.sensit5") public class AppConfig implements WebMvcConfigurer { @Bean public ViewResolver internalResourceViewResolver() { InternalResourceViewResolver bean = new InternalResourceViewResolver(); bean.setViewClass(JstlView.class); bean.setPrefix("/WEB-INF/views/"); bean.setSuffix(".jsp"); return bean; } @Bean(name="localeResolver") public LocaleContextResolver getLocaleContextResolver() { SessionLocaleResolver localeResolver = new SessionLocaleResolver(); localeResolver.setDefaultLocale(new Locale("pl","PL")); return localeResolver; } @Override public void addResourceHandlers(ResourceHandlerRegistry handlerRegistry) { handlerRegistry.addResourceHandler("/resources/**").addResourceLocations("/resources/"); } }
HomePageController.java
package pl.krzysztofskul.sensit5; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class HomePageController { @GetMapping({"/home", "/"}) public String home() { return "index"; } @GetMapping("/test/home") @ResponseBody public String testHome() { return "test home sensit5"; } }
问题分析与解决方案
核心问题
Railway.app默认不提供外部Tomcat容器,你的项目当前仅打包为WAR包,依赖外部容器运行,无法在Railway的环境中独立启动;同时pom.xml中同时配置了maven-jar-plugin和maven-war-plugin,存在配置冲突。
修复步骤
1. 添加嵌入式Tomcat依赖
在pom.xml的<dependencies>中添加嵌入式Tomcat依赖,让WAR包可以独立运行:
<dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-core</artifactId> <version>9.0.65</version> <!-- 与servlet-api 4.0.1兼容 --> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <version>9.0.65</version> </dependency>
2. 移除冲突的JAR插件配置
删除pom.xml中的maven-jar-plugin配置(WAR项目无需生成可执行JAR):
<!-- 删除以下这段配置 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.1.0</version> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> <mainClass>pl.krzysztofskul.sensit5.App</mainClass> </manifest> </archive> </configuration> </plugin>
3. 修改启动类,支持嵌入式Tomcat启动
更新App.java,添加Tomcat启动逻辑,适配Railway的端口环境变量:
package pl.krzysztofskul.sensit5; import org.apache.catalina.Context; import org.apache.catalina.LifecycleException; import org.apache.catalina.startup.Tomcat; import javax.servlet.Filter; import org.springframework.web.filter.CharacterEncodingFilter; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; import java.io.File; public class App extends AbstractAnnotationConfigDispatcherServletInitializer { public static void main(String[] args) throws LifecycleException { Tomcat tomcat = new Tomcat(); // 读取Railway分配的端口,默认8080 String port = System.getenv("PORT"); tomcat.setPort(port != null ? Integer.parseInt(port) : 8080); // 设置webapp目录路径 String webappDirLocation = "src/main/webapp/"; tomcat.addWebapp("", new File(webappDirLocation).getAbsolutePath()); Context context = tomcat.getHost().findChild(""); // 注册DispatcherServlet初始化器 context.addServletContainerInitializer(new App(), null); tomcat.start(); tomcat.getServer().await(); } @Override protected Class<?>[] getRootConfigClasses() { return null; } @Override protected Class<?>[] getServletConfigClasses() { return new Class[]{AppConfig.class}; } @Override protected String[] getServletMappings() { return new String[]{"/"}; } @Override protected Filter[] getServletFilters() { CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); characterEncodingFilter.setEncoding("UTF-8"); return new Filter[] { characterEncodingFilter }; } }
4. 添加Railway启动配置
在项目根目录创建Procfile文件,内容为:
web: java -jar target/sensit5-0.0.1-SNAPSHOT.war
5. 重新打包部署
执行mvn clean package生成WAR包,推送到GitHub后触发Railway重新部署。
额外检查
- 确认Railway的Java运行环境为8,与项目配置一致
- 查看Railway的应用日志,排查是否有端口占用、依赖缺失等具体错误
- 确保
WEB-INF/views目录下存在index.jsp文件
内容的提问来源于stack exchange,提问作者krzysztofskul
相关产品推荐
相关产品推荐

