Project: Spring Boot WAR on Tomcat
Introduction
This capstone converts a minimal Spring Boot 3 REST app from executable JAR thinking to WAR on external Tomcat, deploys beside your Servlet WAR, and compares verification steps with java -jar. It applies Spring Boot WAR on Tomcat end-to-end.
Prerequisites
- Spring Boot first project concepts
- Tomcat 10.1 + Project: Nginx + Tomcat (optional Nginx)
- JDK 17+, Maven 3.9+
Project Goals
- Boot app
demo-api.warwithGET /api/status - Deploy to Tomcat at
/demo-api - Checklist comparing JAR vs WAR deploy
Step 1: Create Boot WAR Project
bash
# Or start from start.spring.io: Maven, Jar→change to War, Spring Web, Boot 3, Java 17
mkdir -p demo-api/src/main/java/com/example/demo
mkdir -p demo-api/src/main/resources
cd demo-apipom.xml (essential parts):
xml
DemoApplication.java:
java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}ServletInitializer.java:
java
package com.example.demo;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(DemoApplication.class);
}
}StatusController.java:
java
application.properties:
properties
server.forward-headers-strategy=frameworkStep 2: Build and Deploy
bash
mvn clean package
export CATALINA_HOME=/opt/tomcat
$CATALINA_HOME/bin/shutdown.sh
cp target/demo-api.war $CATALINA_HOME/webapps/
# blog-api.war can remain — multiple WARs coexist
$CATALINA_HOME/bin/startup.sh
tail -30 $CATALINA_HOME/logs/catalina.$(date +%Y-%m-%d).logVerify:
bash
curl -s http://127.0.0.1:8080/demo-api/api/statusExpected JSON with external-tomcat.
Step 3: JAR vs WAR Comparison Checklist
| Check | Executable JAR | WAR on Tomcat |
|---|---|---|
| Run command | java -jar demo.jar | startup.sh (Tomcat) |
| Tomcat in artifact | Embedded in JAR | provided — external |
| Context path | server.servlet.context-path or / | WAR name demo-api → /demo-api |
| Config | application.yml | Same |
| Logs | Console / file per app | logs/localhost.*.log |
| Multiple apps | One JAR per process | Multiple WARs one JVM |
| Nginx upstream | proxy_pass :8080 | Same — mind context paths |
Step 4: Nginx Location (If Using Project 18)
Add to Nginx server block:
nginx
location /demo-api/ {
proxy_pass http://127.0.0.1:8080/demo-api/;
include /etc/nginx/proxy_params;
}bash
curl -H "Host: app.example.com" http://127.0.0.1/demo-api/api/statusStep 5: Actuator (Optional)
Add spring-boot-starter-actuator, configure exposure, hit:
bash
curl http://127.0.0.1:8080/demo-api/actuator/healthRestrict public access in production.
Acceptance Checklist
-
ServletInitializerpresent - Tomcat starter
provided - Boot starts in Tomcat logs without
ClassNotFoundException -
/demo-api/api/statusreturns JSON - Can explain one JAR vs WAR tradeoff from checklist
Troubleshooting
| Issue | Fix |
|---|---|
| 404 | URL must include /demo-api prefix |
| Works as JAR, fails as WAR | Missing ServletInitializer |
NoSuchMethodError | Embedded Tomcat not provided |
Track Complete
You have deployed plain Servlet WAR, external docBase, Nginx + Tomcat, and Spring Boot WAR. Continue with Troubleshooting and the chapter index.