Hello old friend!

How to write a Java EE application using Spring Boot and Docker on NetBeans IDE 8.2

Nebrass Lamouchi
NetBeans IDE 8.2

Granite mortar and pestle with spices image via Shutterstock

NetBeans Dream Team member Nebrass Lamouchi wrote a tutorial on how to write a Java EE application using Spring Boot and Docker in NetBeans IDE but now it’s time to dive deeper into the topic and experiment with NetBeans IDE 8.2.

Today I’d like to share with you how to write a Java EE application using two of the actual trendiest technologies: Spring Boot & Docker on NetBeans IDE 8.2

Spring Boot is an innovative project that aims to make it easy creating spring applications, by simplifying the configuration and deployment actions through its convention over configuration based setup.

Spring Boot provide a radically faster and widely accessible getting started development experience for all Spring development. Docker is an open-source project that automates the deployment of applications inside software containers.

Today I want to write a small tutorial of a simple Spring Boot application that will be deployed using Docker.

Requirements:

  • JDK 8 is highly recommended
  • We need Docker, which only runs on 64-bit machines. See here for details on setting Docker up for your machine. Before proceeding further, verify you can run docker commands from the shell. If you are using boot2docker you need to run that first.
  • NetBeans IDE 8.2, to be downloaded from here.

For this tutorial I will be using the version 8.2 of NetBeans IDE, which embedded the Docker support.

 

NetBeans IDE 8.2

Grab the Java EE bundle from the download section.

Docker support

To connect to a Docker instance, make sure that the Docker daemon is started.

After installation, check you docker-machine:

docker-machine ls

If you don’t have any docker-machine, you can create a new docker-machine:

docker-machine create -- driver virtualbox default

The output will be like this:

Running pre-create checks...
Creating machine...
(default) Copying /Users/nebrass/.docker/machine/cache/boot2docker.iso to
/Users/nebrass/.docker/machine/machines/default/boot2docker.iso...
(default) Creating VirtualBox VM...
(default) Creating SSH key...
(default) Starting the VM...
(default) Check network to re-create if needed...
(default) Waiting for an IP...
Waiting for machine to be running, this may take a few minutes...
Detecting operating system of created instance...
Waiting for SSH to be available...
Detecting the provisioner...
Provisioning with boot2docker...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
Checking connection to Docker...
Docker is up and running!
To see how to connect your Docker Client to the Docker Engine running on this virtual machine,
run: docker-machine env default

To connect you Docker Client to the created docker-machine, run:

docker-machine env default

And finally to apply the environment variables of the created docker-machine:

eval $(docker-machine env default)

Now, our Docker environment is ready to use :)

The Docker section is available in the Services window.

On NetBeans go to the Services window:

NetBeans IDE 8.2

Next,

NetBeans IDE 8.2

After configuring the Docker instance, you can see all your Images and Containers, with the state of each container:

NetBeans IDE 8.2

The Docker integration in NetBeans supports many Docker operations such as running or pushing images, or starting and stopping containers:

NetBeans IDE 8.2 NetBeans IDE 8.2

Now, we paired our created Docker Machine with our IDE.

Spring Boot support

We have a great Spring Boot plugin: NB-SpringBoot created by Alex Falappa.

The features provided by the plugin:

  • New Spring Boot Maven project wizards:
    • Basic project
    • Project generated by Spring Initializr service
  • Enhanced properties file editor:
    • completion and documentation of configuration properties names
    • completion and documentation of configuration properties values (hints in configuration metadata)
  • Spring Boot file templates:
    • CommandlineRunner annotated classes
    • ApplicationRunner annotated classes
    • application.properties files
    • ConfigurationProperties annotated classes
    • additional-spring- configuration-metadata.json files
  • Additional Spring Framework file templates:
    • Component annotated classes
    • Configuration annotated classes
    • Service annotated classes
    • Controller annotated classes (Spring MVC)
    • RestController annotated classes (Spring MVC)
    • interfaces extending Repository (Spring Data)
  • Additional code generators in pom.xml files:
    • Add Spring Boot dependencies (dependency metadata is taken from the Spring Initializr web service)
    • Add basic Spring Boot setup
  • Toolbar button to trigger Spring Boot devtools reload
  • Specific Spring Boot project properties page to:
    • Specify command line run arguments and launch VM options
    • Enable/disable manual devtools reload trigger
    • Toggle debug mode and color output
    • Assisted override of configuration properties at launch
  • Additional navigator panel to show request URL mappings of a Controller / RestController class

Creating our boot application

After installing the plugin, we can create a new project using the Spring Initializr directly from NetBeans:

NetBeans IDE 8.2

Next,

NetBeans IDE 8.2

Next, select the Spring Boot version & the needed dependencies.

NetBeans IDE 8.2

I just picked the Web, Actuator, JPA & H2 dependencies for our project.

We will start using the H2 dependency, we will move later to PostgreSQL.

Next,

NetBeans IDE 8.2

So now we have created our project base using Spring Initializer.

The structure of the created project:

NetBeans IDE 8.2

After generating our project, we must add the finalName in the build section of the pom.xml:

<build>
	<finalName>nb-springboot-docker</finalName>
	…
</build> 

Now we will create a new JPA Entity:

NetBeans IDE 8.2

Next, create an “Employee” entity, and don’t forget to uncheck the Create Persistence Unit, as the SpringBoot will configure the Persistence Unit automatically.

NetBeans IDE 8.2

An example of Employee entity code can be:

@Entity
public class Employee implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;
    private String email;

    protected Employee() {
    }

    public Employee(String name, String email) {
        this.name = name;
        this.email = email;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Employee employee = (Employee) o;
        return Objects.equals(getName(), employee.getName())
                && Objects.equals(getEmail(), employee.getEmail());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getName(), getEmail());
    }

    @Override
    public String toString() {
        return "Employee{id=[" + id +"], name=[" + name + "], email=[" + email + "]}";
    }
}

Now we will create the Repository, which is the CRUD handler in the Spring Framework:
NetBeans IDE 8.2

We will choose JpaRepository as Base Interface and we will mention our entity class and its Id Class in the Repository Interface creation:

NetBeans IDE 8.2

Now we will create a new RestController, which is the REST Boundary in Spring Framework:

NetBeans IDE 8.2

NetBeans IDE 8.2

Our controller will be:

@RestController
@RequestMapping(path = "/employees", produces = APPLICATION_JSON_VALUE)
public class EmployeeRestController {

    private final EmployeeRepository employeeRepository;

    public EmployeeRestController(EmployeeRepository employeeRepository) {
        this.employeeRepository = employeeRepository;
    }

    @RequestMapping(method = GET)
    public List<Employee> list() {
        return this.employeeRepository.findAll();
    }

    @RequestMapping(value = "/{id}", method = GET)
    public ResponseEntity<Employee> get(@PathVariable Long id) {
        Employee employee = this.employeeRepository.findOne(id);
        if (employee != null) {
            return ResponseEntity.ok(employee);
        }
        return ResponseEntity.notFound().build();
    }

    @RequestMapping(method = POST, consumes = APPLICATION_JSON_VALUE)
    public ResponseEntity<Employee> post(@RequestBody EmployeeDto input) {
        return ResponseEntity
                .ok(
                        this.employeeRepository.save(
                                new Employee(
                                        input.getName(),
                                        input.getEmail())
                        )
                );
    }

    @RequestMapping(value = "/{id}", method = DELETE)
    public ResponseEntity<Employee> delete(@PathVariable Long id) {
        Employee employee = this.employeeRepository.findOne(id);
        if (employee != null) {
            this.employeeRepository.delete(id);
            return ResponseEntity.ok().build();
        }
        return ResponseEntity.notFound().build();
    }
}

For the HTTP service, we created a small DTO to wrap the input:

public class EmployeeDto {

    private String name;
    private String email;

    public EmployeeDto() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

Now, we can start the application and test our webservices.

  • Create a new employee:
    curl
    -H "Content-Type: application/json"
    -X POST -d '{"name":"Nebrass","email":"nebrass@netbeans.org"}' http://localhost:8080/employees
  • List all the employees:
    curl http://localhost:8080/employees

To deploy our application using Docker, we will need to prepare our container.

Now we need to build our first container, which will run our sample microservice. We do this by defining the Dockerfile, which is a text file containing series of commands that tell Docker how to build an image. Once we have written a Dockerfile, we can then repeatedly build an image by running the docker build command.

In NetBeans, create the new Dockerfile:

NetBeans IDE 8.2

Create the “Dockerfile” in the “src/main/docker” folder.

NetBeans IDE 8.2

An example of a Dockerfile content that we can use :

FROM java:8

MAINTAINER Nebrass Lamouchi, nebrass.fr

ADD nb-springboot-docker.jar /app.jar

EXPOSE 8080

CMD java -Djava.security.egd=file:/dev/./urandom -jar /app.jar 

As you can see, the Dockerfile is very simple. It consists of the following instructions:

  • FROM – the FROM instruction specifies the starting image, which in this example is the Java 8 image mentioned above. The first time you build this image, Docker will download the Java 8 image from the central Docker registry
  • MAINTAINER – this instruction simply specifies the author
  • ADD – this instruction copies the JAR file to the specified location in the image. Note that working directory for the dockerfile/java image is /data so that’s why we are putting the JAR file there.
  • EXPOSE – this instruction tells Docker that this server process will listen on port 8080
  • CMD – is the command — we run Java, setting properties, for example, a quick additional property to reduce Tomcat startup time we added a system property pointing to “/dev/urandom” as a source of entropy, and then point it at our j

To build the image you can use some tooling for Maven (Spotify) or Gradle (Transmode).

For our example we will be using Maven.

Build a Docker image with Maven

In the Maven pom.xml you should add a new plugin like this (see the Docker-Maven-Plugin documentation for more options):

<plugin>
    <groupId>com.spotify</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <version>0.4.13</version>
    <configuration>
        <imageName>nebrass/${project.artifactId}</imageName>
        <dockerDirectory>src/main/docker</dockerDirectory>
        <resources>
            <resource>
                <targetPath>/</targetPath>
                <directory>${project.build.directory}</directory>
                <include>${project.build.finalName}.jar</include>
            </resource>
        </resources>
    </configuration>
</plugin>

The plugin configuration is simple:

  • imageName: The name of the generated Docker image, I am prefixing my imageName with my DockerHub ID
  • dockerDirectory: The directory in which to find the Dockerfile
  • resources: The resources files to copy from the target directory to the docker build (alongside the Dockerfile)

You can build an image with the above configurations by running this command:

 mvn clean package docker:build 

After the execution of the command, when you check the list of the Docker images, you will find that the built image is added to the list :

NetBeans IDE 8.2

There is also the “java:8” image is added also to the list of images. This is because the “nebrass/nb-springboot-docker” is based on the “java:8” image.

You can run the built image just by clicking on “Run”.

NetBeans IDE 8.2

Next, configure your container:

NetBeans IDE 8.2

Next, configure the ports binding:

NetBeans IDE 8.2

A great feature is provided by NetBeans: « Add Exposed » will bind the exposed ports automatically in the created container.

By clicking on « Finish » the container will be launched, and a log window will appear in NetBeans, to show you how your container is executed:

NetBeans IDE 8.2

Now, we check your application at http://192.168.99.100:8080/employees

NetBeans IDE 8.2

Great ! This is working !

Run Docker container from Maven & NetBeans

Optionally, we can add a Maven Task, that we will be used to run the container. It can be used for example to bind the task to some Maven Phase (package, deploy…).

The command line used to launch the container :

 docker run –d –p 8080:8080 nebrass/nb-springboot-docker 

So our Maven Task will execute the same command. We will use the “exec-maven-plugin” to launch the same command:

 <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <executions>
        <execution>
            <id>DockerRun</id>
            <goals>
                <goal>exec</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <executable>/usr/local/bin/docker</executable>
        <arguments>
            <argument>run</argument>
            <argument>-d</argument>
            <argument>-p</argument>
            <argument>8080:8080</argument>
            <argument>nebrass/${project.artifactId}</argument>
        </arguments>
    </configuration>
</plugin>

So to run the container from Maven:

 mvn exec:exec 

The output:

 [INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building nb-springboot-docker 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- exec-maven-plugin:1.3.2:exec (default-cli) @ nb-springboot-docker ---
bf17bdaf0d9cb74e9fb94b20f9865d4424442413cd12a21804e252cce0976354
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.051 s
[INFO] Finished at: 2016-07-06T22:25:25+02:00
[INFO] Final Memory: 14M/245M
[INFO] ------------------------------------------------------------------------

The app now is deployed and running in the created docker container and our Greetings service is accessible at http://DOCKER_HOST:8080/employees (docker ps to list running containers).

The global Maven command that does the build, test, create the docker image and run it:

 mvn clean install docker:build exec:exec 

This is the command that I added to my NetBeans as custom Maven Goal:

NetBeans IDE 8.2

NetBeans IDE 8.2

The output in NetBeans:

NetBeans IDE 8.2

Doing more with Docker Compose

Now we can upgrade our application, to use the PostgreSQL instead of H2.

The first thing to do is to add the PostgreSQL Dependency to our pom.xml:

<dependency>
     <groupId>postgresql</groupId>
     <artifactId>postgresql</artifactId>
     <version>9.1-901-1.jdbc4</version>
</dependency> 

Don’t forget to remove the H2 dependency. :)

We will be using a PostgreSQL Docker Container. The command will be:

docker run -d \
     --name demo-postgres \
     -e POSTGRES_USER=developer
     -e POSTGRES_PASSWORD=p4SSW0rd \
     -e POSTGRES_DB=demo \
     -p 5432:5432 postgres:latest

Our Docker Run command of PostgreSQL included the username, password, and the DB name; these details has to be mentioned in our “application.properties” so that our Application can connect to the PostgreSQL Container:

NetBeans IDE 8.2

For the Datasource URL, we mentioned that “postgres” is the HOST. Don’t be scared, Docker will be resolving this DNS Hostname for us. :)

We start by creating a new YAML file, which will be our Docker-compose File:

NetBeans IDE 8.2

Our docker-compose file content can be:

version: '2'
services:
    nb-springboot-docker-app:
        image: nebrass/nb-springboot-docker
        external_links:
            - db:postgres
        ports:
            - 8080:8080
            - 8000:8000
    db:
        image: postgres
        environment:
            - POSTGRES_DB=demo
            - POSTGRES_PASSWORD=p4SSW0rd
            - POSTGRES_USER=developer
        ports:
            - 5432:5432

We can start our docker-compose stack by:
docker-compose -f src/main/docker/app.yml up

And the stack will be created and started.
We can check our app on http://localhost:8080/employees

Let’s debug our Dockerized app

Based on the SpringBoot Reference Guide, to start our app in the Debug Mode, just add these parameters to the lunch command:

 -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n 

Our Dockerfile will be:

FROM java:8

MAINTAINER Nebrass Lamouchi, nebrass.fr

ADD nb-springboot-docker.jar /app.jar

EXPOSE 8000 8080

CMD java -Djava.security.egd=file:/dev/./urandom -jar -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n /app.jar

The next step, is to attach NetBeans to the remote Debugging.
From the menu, click Debug > Attach Debugger.

NetBeans IDE 8.2

Verify that the port is 8000:

NetBeans IDE 8.2

Let’s try it!

I will put a breakpoint, in the Rest Service, and I will test if my NetBeans can catch me. :D

NetBeans IDE 8.2

Got it ! :) We are debugging our Dockerized App from our NetBeans IDE.

Summary

Congratulations! You have created a Spring Boot Microservice that is executed and deployed in a Docker container that can be configured and managed, at the same place with the Spring Boot application.

We also discovered in this tutorial, the great Docker Integration in NetBeans 8.2.

The Spring Boot plugin developed by Alex Falappa is a great add-on from the community and worth a try, you will love it for sure ;)

 

Author
Nebrass Lamouchi
Nebrass Lamouchi is a Java Developer & an OWASP Project Leader. He lives and works in Paris. He is a Java technology enthusiast, trainer and speaker. Recently, Nebrass joined the NetBeans Dream Team. He holds an M.Sc in Information Systems Security from ISG Tunis, Tunisia.

Comments
comments powered by Disqus