Saturday, October 14, 2017

Deploy Java Web Application on Heroku with Heroku CLI

This post will describe how to create and deploy a Java Web Application war to Heroku using Heroku CLI. You will need a basic understanding of Git and Maven, and have Git and Maven already installed on your system.
Pre-requisites
  • Install Java 8, Maven and Git. For this post, I used Java 8 and Maven 3.5.
  • Create a free account on heroku.com. This account will be used from Heroku CLI to login
  • Download and Install Heroku CLI from here.
Following are the high-level steps to follow
  1. Create a Simple Spring Web Application.
  2. Create an application on Heroku
  3. Create the Procfile
  4. Create app.json
  5. Update Maven pom.xml
  6. Push code to Heroku

Create a Simple Spring Web Application

We will use a very basic spring boot web application which will show a Hello World Screen. We will have only two Java files
  • SpringWebApplication.java: This is the spring boot main class
  • HelloWorld: This is a simple Spring Controller which will print Hellow World to the screen.
The following is the folder structure.
HelloWorld.java
package com.blogspot.javax.springweb;


import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloWorld {

    @RequestMapping("/")
    public String index() {
        return "Hello World";
    }

}
SpringWebApplication.java
package com.blogspot.javax.springweb;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;

@SpringBootApplication
public class SpringWebApplication extends SpringBootServletInitializer {
 @Override
 protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
  return application.sources(SpringWebApplication.class);
 }

 public static void main(String[] args) {
  SpringApplication.run(SpringWebApplication.class, args);
 }
}
The maven pom.xml file is at the end of this post.

Create a Heroku Application using Heroku CLI

Follow these steps to create a heroku application.
  1. Open up a command line and login to heroku using the credentials of your heroku account
    C:\workspaces\aoj\spring-web>heroku login
    Enter your Heroku credentials:
    Email: ******@******.***
    Password: ********
    Logged in as ******@******.***
  2. Create an application on Heroku using heroku create command. You can pass any name, and heroku will create the app if the name is available. If you do not pass any name, heroku will pick a name for you, and you can rename it later.
    C:\workspaces\aoj\spring-web>heroku create 
    Creating ... done
    https://.herokuapp.com/ | https://git.heroku.com/.git

Create the Procfile

A Procfile is a mechanism for declaring what commands are run by your application’s dynos on the Heroku platform. The name "Procfile" should be used as is, without extensions and is case-sensitive. This file has to be place in the application root directory. For our simple Web application, we will use webapprunner, which can be used for tomcat based applications
web:    java $JAVA_OPTS -jar target/dependency/webapp-runner.jar --port $PORT target/*.war
Here we specify that it is a web application and the command to be run is the webapp-runner.jar.

app.json

This file can be used to describe the application details, setup configurations and runtime environments in a structured way. In our example, we just print the application name and description in this file. The app.json file should also be at the root folder of the application
{
  "name": "Spring Web",
  "description": "Spring Boot WebApp"
}

Add the WebAppRunner plugin to Maven

Add the following plugin to Maven pom.xml
<build>
  <plugins>

    .......

    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-dependency-plugin</artifactId>
      <version>2.3</version>
      <executions>
        <execution>
          <phase>package</phase>
          <goals>
            <goal>copy</goal>
          </goals>
          <configuration>
            <artifactItems>
              <artifactItem>
                <groupId>com.github.jsimone</groupId>
                <artifactId>webapp-runner</artifactId>
                <version>8.5.23.0</version>
                <destFileName>webapp-runner.jar</destFileName>
              </artifactItem>
            </artifactItems>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

Push Code to Heroku to Deploy

You can push the code to Heroku. And based on the pom.xml, Heroku will detect that this is a Java project and attempt to deploy it.
C:\workspaces\aoj\spring-web>git add .
warning: LF will be replaced by CRLF in .mvn/wrapper/maven-wrapper.properties.
The file will have its original line endings in your working directory.
warning: LF will be replaced by CRLF in pom.xml.
The file will have its original line endings in your working directory.
warning: LF will be replaced by CRLF in src/test/java/com/blogspot/javax/springweb/SpringWebApplicationTests.java.
The file will have its original line endings in your working directory.

C:\workspaces\aoj\spring-web>git commit -m "initial"
[master c911ee8] initial
 2 files changed, 134 insertions(+), 31 deletions(-)
 create mode 100644 out.txt

C:\workspaces\aoj\spring-web>git push heroku master
Once deployed, Heroku will give you the URL at the end of the command as shown below.
remote:        [INFO] ------------------------------------------------------
remote:        [INFO] BUILD SUCCESS
remote:        [INFO] ------------------------------------------------------
remote:        [INFO] Total time: 6.173 s
remote:        [INFO] Finished at: 2017-10-14T15:07:16+00:00
remote:        [INFO] Final Memory: 34M/297M
remote:        [INFO] ------------------------------------------------------
remote: -----> Discovering process types
remote:        Procfile declares types -> web
remote:
remote: -----> Compressing...
remote:        Done: 92.7M
remote: -----> Launching...
remote:        Released v5
remote:        https://.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/.git
   02fac92..c911ee8  master -> master

Folder Structure


spring-web
│   .classpath
│   .gitignore
│   .project
│   app.json
│   out.txt
│   pom.xmlProcfile
│
├───.mvn
│   └───wrapper
│           maven-wrapper.jar
│           maven-wrapper.properties
│
├───.settings
│       org.eclipse.core.resources.prefs
│       org.eclipse.jdt.core.prefs
│       org.eclipse.m2e.core.prefs
│
└───src
    ├───main
    │   ├───java
    │   │   └───com
    │   │       └───blogspot
    │   │           └───javax
    │   │               └───springweb
    │   │                       HelloWorld.java
    │   │                       SpringWebApplication.java
    │   │
    │   └───resources
    │       │   application.properties
    │       │
    │       ├───static
    │       └───templates
    └───test
        └───java
            └───com
                └───blogspot
                    └───javax
                        └───springweb
                                SpringWebApplicationTests.java

Full pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project>
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.blogspot.java-x</groupId>
  <artifactId>spring-web</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>spring-web</name>
  <description>Demo project for Spring Boot</description>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.7.RELEASE</version>
    <relativePath /> <!-- lookup parent from repository -->
  </parent>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </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>

      <plugin>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <version>9.3.7.v20160115</version>
      </plugin>

      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.6.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.0.0</version>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <version>2.3</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>copy</goal>
            </goals>
            <configuration>
              <artifactItems>
                <artifactItem>
                  <groupId>com.github.jsimone</groupId>
                  <artifactId>webapp-runner</artifactId>
                  <version>8.5.23.0</version>
                  <destFileName>webapp-runner.jar</destFileName>
                </artifactItem>
              </artifactItems>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>


</project>

2 comments:

Popular Posts