I am trying to deploy the Spring Boot Application with WAR packaging to Tomcat 10
. The application gets deployed successfully, however, when I try to access the endpoints it results in 404 Not Found.
WAR File: application.war
http://localhost:8080/application/api/abc -> 404 Not Found (Spring Boot Endpoint) http://localhost:8080/application/abc -> 404 Not Found (Angular URL which calls /api/abc)
Tomcat webapps/application
folder consists of following and index.html
(Angular) have <base href="/">
As discussed here, I have added a class AppServletInitializer
which extends SpringBootServletInitializer
as follow
@Configuration public class AppServletInitializer extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(SpringApp.class); } }
In pom.xml, I have added the dependency for spring-boot-starter-tomcat, tomcat-embed-jasper and set packaging option as war. I have shared the simplified (removed dependency, plugins. will add the same if required)
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 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.name</groupId> <artifactId>application</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>My Application</name> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.8.RELEASE</version> <relativePath /> </parent> <properties> <!-- Build properties --> <maven.version>3.3.9</maven.version> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.testresult.directory>${project.build.directory}/test-results</project.testresult.directory> <maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format> <maven.compiler.source>${java.version}</maven.compiler.source> <maven.compiler.target>${java.version}</maven.compiler.target> <argLine>-Djava.security.egd=file:/dev/./urandom -Xmx256m</argLine> <m2e.apt.activation>jdt_apt</m2e.apt.activation> <run.addResources>false</run.addResources> <jhipster-dependencies.version>3.0.5</jhipster-dependencies.version> <spring-boot.version>2.1.8.RELEASE</spring-boot.version> <spring.version>5.1.9.RELEASE</spring.version> <hibernate.version>5.3.11.Final</hibernate.version> <javassist.version>3.23.2-GA</javassist.version> <maven-clean-plugin.version>3.1.0</maven-clean-plugin.version> <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version> <maven-javadoc-plugin.version>3.1.1</maven-javadoc-plugin.version> <maven-resources-plugin.version>3.1.0</maven-resources-plugin.version> <maven-war-plugin.version>3.2.3</maven-war-plugin.version> <properties-maven-plugin.version>1.0.0</properties-maven-plugin.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>junit</groupId> <artifactId>junit</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <build> <defaultGoal>spring-boot:run</defaultGoal> <finalName>application</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>${java.version}</source> <target>${java.version}</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> <configuration> <mainClass>${start-class}</mainClass> <fork>true</fork> </configuration> </plugin> </plugins> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>${maven-compiler-plugin.version}</version> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring-boot.version}</version> </plugin> </plugins> </pluginManagement> </build> <profiles> <profile> <id>dev</id> <activation> <activeByDefault>true</activeByDefault> </activation> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> </dependencies> </profile> <profile> <id>prod</id> <build> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <configuration> <filesets> <fileset> <directory>target/classes/static/</directory> </fileset> </filesets> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <mainClass>${start-class}</mainClass> </configuration> <executions> <execution> <goals> <goal>build-info</goal> </goals> </execution> </executions> </plugin> <!-- <plugin>--> <!-- <groupId>org.apache.maven.plugins</groupId>--> <!-- <artifactId>maven-war-plugin</artifactId>--> <!-- <version>${maven-war-plugin.version}</version>--> <!-- <executions>--> <!-- <execution>--> <!-- <goals>--> <!-- <goal>war</goal>--> <!-- </goals>--> <!-- <phase>package</phase>--> <!-- </execution>--> <!-- </executions>--> <!-- <configuration>--> <!-- <!–<warSourceIncludes>WEB-INF/**,META-INF/**</warSourceIncludes>–>--> <!-- <failOnMissingWebXml>false</failOnMissingWebXml>--> <!-- </configuration>--> <!-- </plugin>--> </plugins> </build> </profile> </profiles> </project>
Application.java
import io.github.jhipster.config.JHipsterConstants; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; import org.springframework.core.env.Environment; @SpringBootApplication @EnableConfigurationProperties({LiquibaseProperties.class, ApplicationProperties.class, AppServletInitializer.class}) public class Application extends SpringBootServletInitializer implements InitializingBean { private static final Logger log = LoggerFactory.getLogger(Application.class); private final Environment env; public Application(Environment env) { this.env = env; } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(Application.class); } @Override public void afterPropertiesSet() throws Exception { Collection<String> activeProfiles = Arrays.asList(env.getActiveProfiles()); if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) { log.error("You have misconfigured your application! It should not run " + "with both the 'dev' and 'prod' profiles at the same time."); } if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_CLOUD)) { log.error("You have misconfigured your application! It should not " + "run with both the 'dev' and 'cloud' profiles at the same time."); } } public static void main(String[] args) { SpringApplication app = new SpringApplication(Application.class); DefaultProfileUtil.addDefaultProfile(app); Environment env = app.run(args).getEnvironment(); logApplicationStartup(env); } private static void logApplicationStartup(Environment env) { String protocol = "http"; if (env.getProperty("server.ssl.key-store") != null) { protocol = "https"; } String serverPort = env.getProperty("server.port"); String contextPath = env.getProperty("server.servlet.context-path"); if (StringUtils.isBlank(contextPath)) { contextPath = "/"; } String hostAddress = "localhost"; try { hostAddress = InetAddress.getLocalHost().getHostAddress(); } catch (UnknownHostException e) { log.warn("The host name could not be determined, using `localhost` as fallback"); } log.info("n----------------------------------------------------------nt" + "Application '{}' is running! Access URLs:nt" + "Local: tt{}://localhost:{}{}nt" + "External: t{}://{}:{}{}nt" + "Profile(s): t{}n----------------------------------------------------------", env.getProperty("spring.application.name"), protocol, serverPort, contextPath, protocol, hostAddress, serverPort, contextPath, env.getActiveProfiles()); } }
application.yml
server: servlet: context-path: /application
We are using Angular on the client-side and resources are located in the static folder.
Environment: Spring Boot 2.1.8, Angular 8, Java 11,
I have already referred, unfortunately, none of them is working for me. Any help would be Appreciated
Advertisement
Answer
The configuration was correct in the Project. As mentioned in the comment, there might be some issue with Tomcat 10 as it was in the alpha version. I have used Tomcat 9 it was working fine.
The configuration are as below.
Step 1: Change the packing option to war in pom.xml
<packaging>war</packaging>
Step 2: extends SpringBootServletInitializer
import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; /** * This is a helper Java class that provides an alternative to creating a {@code web.xml}. * This will be invoked only when the application is deployed to a Servlet container like Tomcat, JBoss etc. */ public class ApplicationWebXml extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(ApplicationApp.class); } }
Step 3: Create WAR file
mvn clean install
And there we go! We can access the endpoints at
http://localhost:8080/context-path/endpoint OR http://localhost:8080/war-filename/endpoint
We can also create the profile for war
as below
<properties> <maven-war-plugin.version>3.2.3</maven-war-plugin.version> </properties> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>${maven-war-plugin.version}</version> <executions> <execution> <goals> <goal>war</goal> </goals> <phase>package</phase> </execution> </executions> <configuration> <warSourceIncludes>WEB-INF/**,META-INF/**</warSourceIncludes> <failOnMissingWebXml>false</failOnMissingWebXml> <warSourceDirectory>target/classes/static/</warSourceDirectory> <webResources> <resource> <directory>src/main/webapp</directory> <includes> <include>WEB-INF/**</include> </includes> </resource> </webResources> </configuration> </plugin> </plugins> </pluginManagement> </build> <profiles> <profile> <id>war</id> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> </plugin> </plugins> </build> </profile> </profiles>