Deploying a Spring Boot REST Application to Oracle Cloud

05 Nov 2018
6 mins read

In this article we will learn how to develop a simple Java Spring Boot 2 REST application and deploy it on Oracle Application Container Cloud.

Before we get started, here is a list of what we need to complete this tutorial:

Content:

Creating the REST Spring Boot application

To create the Spring Boot application, we’ll use start.spring.io, which will provide us some bootstrap code (main class and pom.xml files). We need the Web, JPA, Lombok and H2 packages for this example:

We will use H2 for database access, which is a in memory database. We’ll connect to a real database in a next article of this series.

Download the zip file, extract its contents to your workspace and open it in your favorite IDE.

Project Structure

The following screenshot shows the structure of the project we will create.

Creating the model (JPA Entity)

The first class we will create is the JPA Entity. We will create a class Contact with a primary key id:

@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
public class Contact {

    @Id
    @GeneratedValue
    private Long id;

    private String name;
    private String email;
    private String phone;
}

The following annotations are from project Lombok and help us keep our classes (specially model/POJO) cleaner without the getters and setters:

Check this link to configure Lombok in Eclipse.

Install this plugin to configure Lombok in IntelliJ IDEA.

When you run the application, you can launch H2 console at http://localhost:8080/h2-console.

You will see that a table called contact was created in H2 Console with all columns we specified as properties in our class.

Creating the JPA Repository

To easily access the mehotds to manipulate the Contact table, we just need to create an interface that extends JpaRepository passing the class that represents our model and the type of the primary key as generic arguments:

@Repository
public interface ContactRepository 
    extends JpaRepository<Contact, Long> { }

Creating the Controller

To access our data, we will also need a Controller.

For testing purposes, we will only expose two methods: find all and find by id:

@RestController
@RequestMapping({"/contacts"})
public class ContactController {

    private ContactRepository repository;

    ContactController(ContactRepository contactRepository) {
        this.repository = contactRepository;
    }

    @GetMapping
    public List findAll(){
        return repository.findAll();
    }

    @GetMapping(path = {"/{id}"})
    public ResponseEntity<Contact> findById(@PathVariable long id){
        return repository.findById(id)
                .map(record -> ResponseEntity.ok().body(record))
                .orElse(ResponseEntity.notFound().build());
    }
}

Please note we are not using the @Autowired annotation to automatically inject the repository. We are using dependency injection through the constructor as it is a recommended best practice.

As this is a simple example, we are not creating a Service class to iterate with the repository. Creating a service layer is a good practice as we can keep our controller class clean and add any required business logic to the service instead.

Initializing the H2 database

As a last step, we are going to insert a few records in the H2 contact table by declaring a Bean that returns a CommandLineRunner:

@SpringBootApplication
public class SpringCloudHelloApplication {

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

	@Bean
	CommandLineRunner init(ContactRepository repository) {
		return args -> {
			repository.deleteAll();
			LongStream.range(1, 11)
					.mapToObj(i -> new Contact(i, "Contact " + i, "contact" + i + "@email.com", "(111) 111-1111"))
					.map(v -> repository.save(v))
					.forEach(System.out::println);
		};
	}
}

To test if our application is working, we can access http://localhost:8080/contacts:

Preparing the build for Oracle Cloud

Now that our code is complete, we can focus on preparaing the application to be deployed to Oracle Cloud.

Depending on the service we will be using the steps are different. In this example, we will use the Oracle Application Container Cloud. The Application Container Cloud includes Oracle Java SE Cloud Service, which makes the steps much simpler.

Dynamically reading the PORT Environment Variable

Locally, our code runs on port 8080. When we deploy the application, we do not know what port is going to be assigned. For this reason, we need to add the following configuration inside src/main/application.properties file:

server.port=${PORT}

Creating the manifest.json file

One of the requirenments to deploy to the Oracle Application Container Cloud is having a manifest.json file. This file needs to be created at the same level as the pom.xml file:

{
  "runtime":{
    "majorVersion": "8"
  },
  "command": "java -jar spring-cloud-hello-0.0.1-SNAPSHOT.jar",
  "release": {
    "build": "2018",
    "commit": "oracle cloud example",
    "version": "0.0.1-SNAPSHOT"
  },
  "notes": "REST Spring Boot 2 app Oracle Cloud"
}

For more information about manifest.json, please refer to this link.

We are declaring that this application needs Java 8 to run, the command (spring boot application) to bootstrap the application and some release notes.

At the time this article is being written, the following Java versions are supported by this service: 7, 8, 9, 10.

Creating a zip file

We need to upload a .zip, .tgz, or .tar.gz file to Oracle Cloud. The zip file must contain the jar file and also the manifest.json file. We can compile the project and manually create the .zip file.

As we are using maven, we can also use the maven-assembly-plugin to create the .zip file with everything we need.

To do so, we first need to create an XML file with the list of files we want to include and the extension.

Below is the content of src/assembly/distribution.xml:

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
    <id>dist</id>
    <formats>
        <format>zip</format>
    </formats>
    <includeBaseDirectory>false</includeBaseDirectory>
    <fileSets>
        <fileSet>
            <directory>${project.basedir}</directory>
            <includes>
                <include>manifest.json</include>
            </includes>
        </fileSet>
        <fileSet>
            <directory>${project.build.directory}</directory>
            <outputDirectory>\</outputDirectory>
            <includes>
                <include>spring-cloud-hello-0.0.1-SNAPSHOT.jar</include>
            </includes>
            <excludes>
                <exclude>*.zip</exclude>
            </excludes>
        </fileSet>
    </fileSets>
</assembly>

And inside the pom.xml -> build -> plugins we are going to add the maven-assembly-plugin:

<plugin>
  <artifactId>maven-assembly-plugin</artifactId>
  <version>2.5.5</version>
  <configuration>
    <appendAssemblyId>false</appendAssemblyId>
    <descriptors>
      <descriptor>src/assembly/distribution.xml</descriptor>
    </descriptors>
  </configuration>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
    </execution>
  </executions>
</plugin>

With this in place we can simply run in the terminal:

mvn compile package

And a .zip file will be create inside the target directory. We will upload this file to Oracle Application Container Cloud.

Deploying on Oracle Application Container Cloud

Open the Oracle Application Container Cloud Service console.

You can access the Application Container service from your console - the link is something like this https://myservices-xxxxxx.console.oraclecloud.com/mycloud/cloudportal/dashboard or you can try to access the service console directly: https://psm-xxxxxx.console.oraclecloud.com/apaas/index.html

It will look something like this:

Click on Create Application and select Java SE:

Provide a name, select the .zip file from the target directory. If you don’t provide the manifest.json along the .zip file, you can also upload it separetely.

For more information about each option available, please refer to this link.

Click on Create. It will take a few seconds to deploy the application. Once the application has been successfully deployed, you will see the link to access it:

Now we can access our API from the cloud:

In case of any issues or if you need to update the .zip file, click on the name of the application -> Deployments -> select a new archive and click on Apply Edits.

Conclusion

These are very simple steps we can use to get started with a cloud environment. Ideally, we would have a complete infrastructure using Continuous Integration (CI) to automatically deploy our application trigged by a new commit to the source code repository.

Also, this example did not cover connecting to a real database. We will learn how to do this in the next article of this series.

Part 2 of this series of blog posts coming soon

Source code

Source code available on GitHub

References:

Happy coding!