Published on Feb 9 2018 in Java Tomcat

We build proof-of-concept JAR and WAR Spring Boot application and show how to run it on shared cPanel server using any of our Java hosting packages.

We use JDK 8 and Maven 3.2 that are available with any Java hosting package. No IDE will be used but commands typed directly in shell for this simple task.

Check that Java and Maven are ready:

java -version
mvn -v

The below POM allows for generating JAR and WAR with only 1 change: the packaging attribute. First we POM will generate JAR. Later we will update it so that it generates a WAR i.e. add <packaging>war</packaging>. For testing WAR we will use a standalone Tomcat that runs beside.

cat > pom.xml<<EOF
<?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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>SpringBootTester</artifactId>
    <version>0.1</version>
    <packaging>jar</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.2.RELEASE</version>
    </parent>

    <dependencies>

    <!-- Add Tomcat and Spring MVC -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

        <!-- Skip the following dependency if you are not going to use the application with external Tomcat. Embedded Tomcat does not need it. -->
    <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-tomcat</artifactId>
           <scope>provided</scope>
        </dependency>

    </dependencies>

    <!-- We defintely need below for Maven to process Spring Boot apps. -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
EOF

Embedded servlet container dependency is marked as 'provided'. Generated WAR will contain dependencies marked this way in lib-provided directory. In effect you will also be able to run the application using java -jar that we will test below.

Now the Java code. @RestController will allow us to skip creation of view file (template) needed for regular @Controller. @RequestMapping("/") maps application's root URL (not domain URL) to the hello function. If the application will be deployed as ROOT.war then application's root URL will equal domain's root URL.

mkdir -p src/main/java

cat > src/main/java/Example.java<<EOF
package com.example;

import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.web.bind.annotation.*;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;

@RestController
@SpringBootApplication
public class Example extends SpringBootServletInitializer {

    @RequestMapping("/")
    String hello() {
        return "Hello World from JAR or WAR!";
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Example.class);
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(Example.class, args);
    }

}
EOF

Testing embedded Tomcat via 'spring-boot:run'

mvn spring-boot:run

Ctrl+C will shutdown the embedded server. On another terminal reach the URL:

curl http://springboot.budgetjava.com:8080/
Hello World from JAR or WAR!

Testing JAR at custom port

mvn package
java $JAVA_OPTS -Dserver.port=11188 -jar target/SpringBootTester-0.1.jar 
curl http://springboot.budgetjava.com:11188/
Hello World from JAR or WAR!

Ctrl+C will shutdown the process if it runs in foreground. Of course you can leave it running in background and logging to a file by appending &>log & at the end of the java -jar ... command.

Testing WAR in external Tomcat listening on default HTTP port

We need to modify packaging line first.

sed -i -re 's/(<packaging>)jar(<\/packaging>)/\1war\2/' pom.xml
mvn clean package
cp target/SpringBootTester-0.1.war $CATALINA_HOME/webapps

Wait until it deploys by tracing log with tail -f $CATALINA_HOME/logs/catalina.out. On another terminal check:

curl http://springboot.budgetjava.com/SpringBootTester-0.1/
Hello World from JAR or WAR!

You might also have copied it to $CATALINA_HOME/webapps/ROOT.war to have it served at domain's root URL. See how main class changes in MANIFEST.MF depending on what you set in pom.xml:

unzip -c target/SpringBootTester-0.1.war META-INF/MANIFEST.MF | grep Class
Start-Class: com.example.Example
Main-Class: org.springframework.boot.loader.WarLauncher

unzip -c target/SpringBootTester-0.1.jar META-INF/MANIFEST.MF | grep Class
Start-Class: com.example.Example
Main-Class: org.springframework.boot.loader.JarLauncher

There are many alternative ways of presetting server.port for example in src/main/resources/application.properties:

server.port=8888

or in src/main/resources/application.yml

server:
  port: 8888

Here are the SpringBootTester-0.1.jar and SpringBootTester-0.1.war for your reference.