Java single dependency Dockerized HTTP endpoint

Java single dependency Dockerized HTTP endpoint

We will create a Java-based HTTP endpoint, make an executable jar out of it, pack it up in Docker, and run it locally in no time.

This article is intended for beginners, who want to looking for a simple walk-through for running a Java application in Docker.

The vast majority of examples out there describing Java applications in a Dockerized environment include the usage of heavy frameworks like Spring Boot. We want to show here that you don't need much to get an endpoint running with Java in Docker.

In fact, we will only use a single library as a dependency: HttpMate core. For this example, we'll use the LowLevel builder of HttpMate with a single HTTP handler.

The environment used for this example

  • Java 11+
  • Maven 3.5+
  • Java-friendly IDE
  • Docker version 18+
  • Basic understanding of HTTP/bash/Java

The final result is available in this git repo.

Organizing the Project

Let's create our initial project structure:

mkdir -p simple-java-http-docker/src/main/java/com/envimate/examples/http

Let's start with the project's pom file in the root directory that we called here simple-java-http-docker:

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
&lt;groupId&gt;com.envimate.examples&lt;/groupId&gt;
&lt;artifactId&gt;simple-java-http-docker&lt;/artifactId&gt;
&lt;version&gt;0.0.1&lt;/version&gt;

&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;com.envimate.httpmate&lt;/groupId&gt;
        &lt;artifactId&gt;core&lt;/artifactId&gt;
        &lt;version&gt;1.0.21&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;

</project>

Here we have:

  • The standard groupId/artifactId/version definition for our project.
  • The single dependency on the HttpMate core library.

This is enough to start developing our endpoint in the IDE of choice. Most of those have support for Maven-based Java projects.

Application Entrypoint

To start our little server, we will use a simple main method. Let's create the entry to our application as an Application.java file in the directory src/main/java/com/envimate/examples/http that will for now just output the time to the console.

package com.envimate.examples.http;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public final class Application {
public static void main(String[] args) {
final LocalDateTime time = LocalDateTime.now();
final String dateFormatted = time.format(DateTimeFormatter.ISO_TIME);
System.out.println("current time is " + dateFormatted);
}
}

Try to run this class and you will see the current time printed.

Let's make this more functional and separate the part that prints out the time into a lambda function with no argument, a.k.a Supplier.

package com.envimate.examples.http;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.function.Supplier;

public final class Application {
public static void main(String[] args) {
Supplier handler = () -> {
final LocalDateTime time = LocalDateTime.now();
final String dateFormatted = time.format(DateTimeFormatter.ISO_TIME);
return "current time is " + dateFormatted;
};

    System.out.println(handler.get());
}

}

The convenience interface provided by the low-level HttpMate does not look much different, except instead of returning a String, that String is set to the response, alongside with the indication that everything went well (a.k.a. response code 200).

final HttpHandler httpHandler = (request, response) -> {
final LocalDateTime time = LocalDateTime.now();
final String dateFormatted = time.format(DateTimeFormatter.ISO_TIME);

response.setStatus(200);
response.setBody("current time is " + dateFormatted);

};

HttpMate also provides a simple Java HttpServer wrapper - PureJavaEndpoint - that would allow you to start an endpoint without any further dependency.

All we need to do is give it the instance of the HttpMate:

package com.envimate.examples.http;

import com.envimate.httpmate.HttpMate;
import com.envimate.httpmate.convenience.endpoints.PureJavaEndpoint;
import com.envimate.httpmate.convenience.handler.HttpHandler;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import static com.envimate.httpmate.HttpMate.anHttpMateConfiguredAs;
import static com.envimate.httpmate.LowLevelBuilder.LOW_LEVEL;

public final class Application {
public static void main(String[] args) {
final HttpHandler httpHandler = (request, response) -> {
final LocalDateTime time = LocalDateTime.now();
final String dateFormatted = time.format(DateTimeFormatter.ISO_TIME);

        response.setStatus(200);
        response.setBody("current time is " + dateFormatted);
    };

    final HttpMate httpMate = anHttpMateConfiguredAs(LOW_LEVEL)
            .get("/time", httpHandler)
            .build();
    PureJavaEndpoint.pureJavaEndpointFor(httpMate).listeningOnThePort(1337);
}

}

Notice that we have configured our httpHandler to serve the path /time, when invoked with method GET.

It's time to start our application and make some requests:

curl http://localhost:1337/time
current time is 15:09:34.458756

Before we put this all into a Dockerfile, we need to package it as a good-old jar.

Building the Jar

We'd need two maven plugins for that: maven-compiler-plugin and maven-assembly-plugin to build the executable jar.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

&lt;groupId&gt;com.envimate.examples&lt;/groupId&gt;
&lt;artifactId&gt;simple-java-http-docker&lt;/artifactId&gt;
&lt;version&gt;0.0.1&lt;/version&gt;

&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;com.envimate.httpmate&lt;/groupId&gt;
        &lt;artifactId&gt;core&lt;/artifactId&gt;
        &lt;version&gt;1.0.21&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;

&lt;build&gt;
    &lt;plugins&gt;
        &lt;plugin&gt;
            &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
            &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
            &lt;version&gt;3.8.1&lt;/version&gt;
            &lt;configuration&gt;
                &lt;release&gt;${java.version}&lt;/release&gt;
                &lt;source&gt;${java.version}&lt;/source&gt;
                &lt;target&gt;${java.version}&lt;/target&gt;
            &lt;/configuration&gt;
        &lt;/plugin&gt;
        &lt;plugin&gt;
            &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
            &lt;artifactId&gt;maven-assembly-plugin&lt;/artifactId&gt;
            &lt;executions&gt;
                &lt;execution&gt;
                    &lt;phase&gt;package&lt;/phase&gt;
                    &lt;goals&gt;
                        &lt;goal&gt;single&lt;/goal&gt;
                    &lt;/goals&gt;
                    &lt;configuration&gt;
                        &lt;archive&gt;
                            &lt;manifest&gt;
                                &lt;mainClass&gt;
                                    com.envimate.examples.http.Application
                                &lt;/mainClass&gt;
                            &lt;/manifest&gt;
                        &lt;/archive&gt;
                        &lt;descriptorRefs&gt;
                            &lt;descriptorRef&gt;jar-with-dependencies&lt;/descriptorRef&gt;
                        &lt;/descriptorRefs&gt;
                    &lt;/configuration&gt;
                &lt;/execution&gt;
            &lt;/executions&gt;
        &lt;/plugin&gt;
    &lt;/plugins&gt;
&lt;/build&gt;

</project>

Once we have that, let's build our jar:

mvn clean verify

And run the resulting jar:

java -jar target/simple-java-http-docker-0.0.1-jar-with-dependencies.jar

Same curl:

curl http://localhost:1337/time
current time is 15:14:42.992563
Dockerizing the Jar

The Dockerfile looks quite simple:

ROM openjdk:12

ADD target/simple-java-http-docker-0.0.1-jar-with-dependencies.jar /opt/application.jar

EXPOSE 1337

ENTRYPOINT exec java -jar /opt/application.jar

It specifies

  • FROM: which image to use as a base. We will use an openjdk image.
  • ADD: the jar we want to the directory we want.
  • EXPOSE: the port we are listening on.
  • ENTRYPOINT: to the command, we want to execute.

To build and tag our Docker image, we run the following command from the root of the directory:

docker build --tag simple-java-http-docker .

This will produce a docker image that we can run:

docker run --publish 1337:1337 simple-java-http-docker

Notice that we are passing the --publish parameter, which indicates that the exposed 1337 port, is available under the 1337 port of the machine.

Same curl:

curl http://localhost:1337/time
current time is 15:23:04.275515

And that is it: we have our simple HTTP endpoint dockerized!

The Icing

Of course, this is a simplified example, and the endpoint we wrote is not entirely useful. It demonstrates, though, that you don't need tons of libraries just to have a running HTTP endpoint, how easy it is to package a runnable jar, use Docker with your Java application, and the basic usage of the low-level HttpMate.

This kind of two-minute setup can be handy when you need to quickly spin a test HTTP server. The other day I was working on a Twitter-bot (stay tuned for an article about that) and I had to debug what my request really looks like on the receiving side. Obviously, I couldn't ask Twitter to give me a dump of my request, so I needed a simple endpoint, that would output everything possible about my request.

HttpMate's handler provides access to an object called MetaData which is pretty much what it's called — the meta-data of your request, meaning everything available about your request.

Using that object, we can print everything there is to the request.

public final class FakeTwitter {
public static void main(String[] args) {
final HttpMate httpMate = HttpMate.aLowLevelHttpMate()
.callingTheHandler(metaData -> {
System.out.println(metaData);
})
.forRequestPath("/*").andRequestMethods(GET, POST, PUT)
.build();

    PureJavaEndpoint.pureJavaEndpointFor(httpMate).listeningOnThePort(1337);
}

}

The request path /time is now replaced with a pattern, capturing all paths, and we can add all the HTTP methods we are interested in.

Running our FakeTwitter server and issuing request:

curl -XGET http://localhost:1337/some/path/with?someParameter=someValue

We'll see the following output in the console (output formatted for readability: it is a map underneath, so you can format it nicely if you so wish)

{
PATH=Path(path=/some/path/with),
BODY_STRING=,
RAW_QUERY_PARAMETERS={someParameter=someValue},
QUERY_PARAMETERS=QueryParameters(
queryParameters={
QueryParameterKey(key=someParameter)=QueryParameterValue(value=someValue)
}
),
RESPONSE_STATUS=200,
RAW_HEADERS={Accept=/,
Host=localhost:1337,
User-agent=curl/7.61.0},
RAW_METHOD=GET,
IS_HTTP_REQUEST=true,
PATH_PARAMETERS=PathParameters(pathParameters={}),
[email protected],
RESPONSE_HEADERS={},
HEADERS=Headers(headers={HeaderKey(value=user-agent)=HeaderValue(value=curl/7.61.0),
HeaderKey(value=host)=HeaderValue(value=localhost:1337),
HeaderKey(value=accept)=HeaderValue(value=/)}),
CONTENT_TYPE=ContentType(value=null),
RAW_PATH=/some/path/with,
METHOD=GET,
LOGGER=com.envimate.httpmate.logger.Loggers$Lambda$17/[email protected],
HANDLER=com.envimate.examples.http.FakeTwitter$Lambda$18/[email protected]
}

Thanks for reading. If you liked this post, share it with all of your programming buddies!

Further reading

☞ Build a Basic App with Spring Boot and JPA using PostgreSQL

☞ Build a Simple CRUD App with Spring Boot and Vue.js

☞ Introducing TensorFlow.js: Machine Learning in Javascript

☞ An illustrated guide to Kubernetes Networking

☞ Google Kubernetes Engine By Example

☞ AWS DevOps: Introduction to DevOps on AWS

☞ Docker Tutorial for Beginners

☞ Kotlin Microservices With Micronaut, Spring Cloud, and JPA


Originally published on https://dzone.com

Learn Spring Framework and Spring Boot - Build a Spring Web Application

Learn Spring Framework and Spring Boot - Build a Spring Web Application: If you're new to the Spring Framework, this is the course you want to start with. This course covers the core of the Spring Framework, the foundation which all of the other Spring Framework projects are built from.

Build a web application using Spring Framework and *Spring Boot *

If you're new to the Spring Framework, this is the course you want to start with. This course covers the core of the Spring Framework, the foundation which all of the other Spring Framework projects are built from.

In this course, you will learn about important key concepts, such as dependency injection and inversion of control, which are used throughout the Spring Framework. Within the Spring Framework, you have the option of using the traditional XML configuration, or the new Java based configuration. I'll show you step by step how to configure Spring Beans using best practices in XML and Java. I'll also show you how to use Spring to persist data into a database, and Spring MVC to show content from the database on a webpage.

By the time we reach the end of this course, you will be able to build a functioning Spring Web Application.

In this course, you will learn about:

  • Dependency Injection and Inversion of Control (IoC) in the Spring Framework.
  • Spring Boot
  • Using Spring Initializr
  • Using Maven to build Spring Projects
  • How to use JUnit and Mockito to test Spring
  • Java and XML Spring Configuration
  • Spring MVC and Thymeleaf with Bootstrap CSS
  • Spring MVC Test
  • JPA / Hibernate
  • Spring JPA and using DAOs
  • Spring Profiles

Build a Java 8 Spring Boot App with Docker

Build a Java 8 Spring Boot App with Docker

Build a Java 8 Spring Boot App with Docker - In this article, I am going to show you how to develop and run a simple Spring web application using Java 8 without installing Java 8 on your local machine.

Python developers use virtual environments for creating and managing separate environments for different projects, and each using different versions of Python for execution and storing and resolving Python dependencies. Java and many other technologies do not support a virtual environment concept. At this point, Docker comes to our aid.

Docker is a virtualization platform. I am not going dive into details of docker's details. you can find basic information and installation guide from the docker official site.

Once you have the Docker toolbox installed, you do not need install Java 8 or MySQL which are needed in our sample application.

Now, you can download my codes from GitHub.

First, let's check the Docker-compose file:

version : '2'
services:

  springappserver:
    build:
      context: . 
      dockerfile: springapp.dockerfile
    ports: 
      - "8080:8080"
    networks:
      - net-spring-db
    volumes:
      - .:/vol/development
    depends_on:
      - mysqldbserver

  mysqldbserver:
    build:
      context: . 
      dockerfile: mysqldb.dockerfile
    ports:
      - "3306:3306"
    networks:
      - net-spring-db
    environment:
      MYSQL_DATABASE: testdb
      MYSQL_USER: myuser
      MYSQL_PASSWORD: mypassword
      MYSQL_ROOT_PASSWORD: myrootpassword
    container_name: mysqldbserver

networks:
  net-spring-db:
    driver: bridge

We have two servers each on the 'net-spring-db' network. The first one is named 'springappserver' and configured with the springapp.dockerfile, which will be described later. The second one is named as mysqldbserver and configured with the mysqldb.dockerfile, which will be described later.

Now, let's have a look at the springapp.dockerfile:

#
# Java 1.8 & Maven Dockerfile
#
#

# pull base image.
FROM java:8

# maintainer
MAINTAINER Dursun KOC "[email protected]"

# update packages and install maven
RUN  \
  export DEBIAN_FRONTEND=noninteractive && \
  sed -i 's/# \(.*multiverse$\)/\1/g' /etc/apt/sources.list && \
  apt-get update && \
  apt-get -y upgrade && \
  apt-get install -y vim wget curl maven

# attach volumes
VOLUME /vol/development

# create working directory
RUN mkdir -p /vol/development
WORKDIR /vol/development

# maven exec
CMD ["mvn", "clean", "package", "exec:java"]

This Docker file configures a Docker image, which is inherited from a Java 8 image from Docker Hub. Over that Java 8 image, I have installed vim, wget, curl, Maven, and set the volume in order to put my existing projects code. And finally, execute the Maven command to run my application.

Now let's check the mysqldb.dockerfile:

FROM mysql/mysql-server

MAINTAINER Dursun KOC <[email protected]>

# Copy the database initialize script: 
# Contents of /docker-entrypoint-initdb.d are run on mysqld startup
ADD  mysql/ /docker-entrypoint-initdb.d/

This Dockerfile configures a Docker image, which is inherited from the MySQL/mysql-server image from Docker Hub. Over the MySQL image, I put my db-schema creation scripts, which are located in the MySQL folder. I have a single SQL file at this folder — data.sql — in order to create the 'person' table.

Now, let's see application structure.

Our application is started from the src/com/turkcell/softlab/Application.java file, and our only Controller is the PersonController(src/com/turkcell/softlab/controller/PersonController.java).

You can run the whole project with a simple command:

docker-compose up -d

For testing, use the following two commands in your local machine:

  • Create new person:
curl -H "Content-Type: application/json" -X POST -d "{\"first\": \"Mustafa\",\"last\": \"KOÇ\",\"dateofbirth\": 381110400000,\"placeofbirth\": \"Erzincan\"}" "http://192.168.99.100:8080/people"
  • List existing people in the database:
curl -H "Content-Type: application/json" -X GET "http://192.168.99.100:8080/people"

Now, it's your turn! You can dive deeper into Java 8 and Spring Boot using this template.

How to build the MVC Java Web App using Spring Boot and Netbean

How to build the MVC Java Web App using Spring Boot and Netbean

In this tutorial, you'll learn how to build the MVC (Model, View, Controller) Java Web App using Spring Boot and Netbeans 11.1

In this Spring Boot tutorial, we will guide you on how to build the MVC Java web app using Netbeans (we are using Apache Netbeans 11.1). Netbeans IDE development continues by Apache since version 9. You can use Eclipse, Intellij, or JDeveloper as well. By using Spring Boot, building Java web app actually a little bit easier than creating Java projects manually using Maven or Gradle. Especially when we are using Spring Initialzr that will help you to create a set of application bundles with the supported dependencies.

Table of Contents:

  • Step #1: Generate Spring Boot Java Web App
  • Step #2: Create Java Model or Entity Class
  • Step #3: Create Java Repository Interface
  • Step #4: Create Spring MVC Controller
  • Step #5: Create Spring MVC Views
  • Step #6: Run The Spring Boot Java Web App

As you can see in the above table of contents that build MVC Java web app required a few steps. Starting from creating Spring Boot project, Java model, Java repository, Java controller, and Java view. This MVC Java web app also uses a database and we will use an H2 In-Memory database or HSQLDB. For the view, we will use Thymeleaf and Bootstrap. So the following tools, frameworks, and libraries are required for this tutorial:

  1. Java Development Kit (JDK) 8
  2. Gradle
  3. Spring Boot
  4. Spring MVC
  5. Spring Data JPA
  6. H2 Database
  7. Thymeleaf
  8. Webjars Bootstrap
  9. Spring Initializer
  10. Netbeans
  11. Terminal or cmd

We assume that you have to install Netbeans, JDK 8 and Gradle in your machine. So, we need just generate a new Spring Boot Gradle Java Web App.

Step #1: Generate Spring Boot Java Web App

We will create a new Spring Boot Gradle project using Spring Initializer. Spring Initializr provides an extensible API to generate quickstart projects, and to inspect the metadata used to generate projects, for instance, to list the available dependencies and versions. Just go to Spring Initializer web-based Spring project generator then fill the required frameworks and libraries (Spring Web, H2 Database, Thymeleaf, Spring Data JPA, Spring Data JDBC).

After filling all fields, click Generate Project. It will automatically download the zipped project. Next, extract the zipped project to your java projects folder then open the folder from Netbeans IDE a project (use open project menu). Next, from the Projects panel expand the project name (ours: springmvc) then expand Build Scripts and you will see the build.gradle file. Open that file and you will see this project information, plugin, repositories, and dependencies.

plugins {
    id 'org.springframework.boot' version '2.1.9.RELEASE'
    id 'io.spring.dependency-management' version '1.0.8.RELEASE'
    id 'java'
}

group = 'com.djamware'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    runtimeOnly 'com.h2database:h2'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

Add this dependency for Bootstrap and Thymeleaf Layout Dialect inside dependencies body.

dependencies {
  ...
    compile 'org.webjars:bootstrap:3.3.7'
  compile 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:2.4.1'
    ...
}

In Netbeans, right-click the project name then click build to build the project for the first time.

Step #2: Create Java Model or Entity Class

We will create a single table of product data for this Spring MVC Java web app. Now, we will implement the term "M" of the Spring MVC by creating a new Java model or entity. Right-click the project name -> New -> Java Class. Fill the class name as Product, the package name as com.djamware.springmvc.models, and leave other fields as default then click the Finish button. The new Java class automatically opened then replace all Java codes with these codes of Java entity, auto-generation ID, required fields, the constructors, and getter and setter.

package com.djamware.springmvc.models;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String prodName;

    private String prodDesc;

    private String prodImage;

    private Double prodPrice;

    public Product() {
    }

    public Product(String prodName, String prodDesc, String prodImage, Double prodPrice) {
        this.prodName = prodName;
        this.prodDesc = prodDesc;
        this.prodImage = prodImage;
        this.prodPrice = prodPrice;
    }

    public Long getId() {
        return id;
    }

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

    public String getProdName() {
        return prodName;
    }

    public void setProdName(String prodName) {
        this.prodName = prodName;
    }

    public String getProdDesc() {
        return prodDesc;
    }

    public void setProdDesc(String prodDesc) {
        this.prodDesc = prodDesc;
    }

    public String getProdImage() {
        return prodImage;
    }

    public void setProdImage(String prodImage) {
        this.prodImage = prodImage;
    }

    public Double getProdPrice() {
        return prodPrice;
    }

    public void setProdPrice(Double prodPrice) {
        this.prodPrice = prodPrice;
    }

}
Step #3: Create Java Repository Interface

Next, we have to create a User Repository that extends the JPA Repository for the Product model. Right-click the project name -> New -> Java Interface. Fill the class name as ProductRepository, the package name com.djamware.springmvc.repositories, and leave other fields as default then click the Finish button. That newly created file will open then replace all Java codes with these codes.

package com.djamware.springmvc.repositories;

import com.djamware.springmvc.models.Product;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ProductRepository extends JpaRepository<Product, Long> {

    Product findByProdName(final String prodName);

}

As you see, the ProductRepository interface now extends the JpaRepository of Product type and it only has an additional query interface of find product by product name. Since Spring Boot 2.1, overriding is disable by default. So, overriding this ProductRepository will result in this error in runtime.

The bean 'productRepository', defined in null, could not be registered. A bean with that name has already been defined in null and overriding is disabled.

To fix that, just open and edit Resources/application.properties then add this line to enable overriding.

spring.main.allow-bean-definition-overriding=true
Step #4: Create Spring MVC Controller

Now, it's time for C terms of MVC that means Controller. To create it on Netbeans just right click on project name -> New -> Java Class. Fill the class name with ProductController and the package with com.djamware.springmvc.controllers. Leave other fields as default then click the Finish button. That newly created Java class file will be opened automatically. Replace all Java codes with these codes of @Controller, @RequestMapping, @RequestParam, ProductRepository, and all required CRUD methods that return the page for each CRUD operation.

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.djamware.springmvc.controllers;

import com.djamware.springmvc.models.Product;
import com.djamware.springmvc.repositories.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class ProductController {

    @Autowired
    ProductRepository productRepository;

    @RequestMapping("/product")
    public String product(Model model) {
        model.addAttribute("products", productRepository.findAll());
        return "product";
    }

    @RequestMapping("/create")
    public String create(Model model) {
        return "create";
    }

    @RequestMapping("/save")
    public String save(@RequestParam String prodName, @RequestParam String prodDesc, @RequestParam Double prodPrice, @RequestParam String prodImage) {
        Product product = new Product();
        product.setProdName(prodName);
        product.setProdDesc(prodDesc);
        product.setProdImage(prodImage);
        product.setProdPrice(prodPrice);
        productRepository.save(product);

        return "redirect:/show/" + product.getId();
    }

    @RequestMapping("/show/{id}")
    public String show(@PathVariable Long id, Model model) {
        model.addAttribute("product", productRepository.findById(id).orElse(null));
        return "show";
    }

    @RequestMapping("/delete")
    public String delete(@RequestParam Long id) {
        Product product = productRepository.findById(id).orElse(null);
        productRepository.delete(product);

        return "redirect:/product";
    }

    @RequestMapping("/edit/{id}")
    public String edit(@PathVariable Long id, Model model) {
        model.addAttribute("product", productRepository.findById(id).orElse(null));
        return "edit";
    }

    @RequestMapping("/update")
    public String update(@RequestParam Long id, @RequestParam String prodName, @RequestParam String prodDesc, @RequestParam Double prodPrice, @RequestParam String prodImage) {
        Product product = productRepository.findById(id).orElse(null);
        product.setProdName(prodName);
        product.setProdDesc(prodDesc);
        product.setProdImage(prodImage);
        product.setProdPrice(prodPrice);
        productRepository.save(product);

        return "redirect:/show/" + product.getId();
    }

}
Step #5: Create Spring MVC Views

Now, it's the time of V for the View of MVC pattern. Since we are using the Thymeleaf library for view template, so we can create the same layout for all HTML pages. Thymeleaf is a Java XML/XHTML/HTML5 template engine that can work both in web (servlet-based) and non-web environments. It is better suited for serving XHTML/HTML5 at the view layer of MVC-based web applications, but it can process any XML file even in offline environments. To create the layout, first, create a default.html file on the Resources/templates folder then add or replace it with these lines of codes.

<!DOCTYPE html>
<html lang="en"
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
    <head>
        <meta charset="UTF-8"/>
        <title>Default title for my pages</title>
        <link rel="stylesheet" href="/webjars/bootstrap/3.3.7/css/bootstrap.min.css"/>
        <link rel="stylesheet" href="/webjars/bootstrap/3.3.7/css/bootstrap-theme.min.css"/>
        <link rel="stylesheet" href="/css/style.css" />
    </head>
    <body>
        <nav class="navbar navbar-inverse navbar-fixed-top">
            <div class="container">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                        <span class="sr-only">Toggle navigation</span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                    <a class="navbar-brand" href="#">Spring MVC</a>
                </div>
                <div id="navbar" class="collapse navbar-collapse">
                    <ul class="nav navbar-nav">
                        <li class="active"><a href="/product">Home</a></li>
                    </ul>
                </div><!--/.nav-collapse -->
            </div>
        </nav>

        <div class="container">
            <div class="starter-template" layout:fragment="content"></div>
        </div><!-- /.container -->

        <script src="/webjars/jquery/1.11.1/jquery.min.js"></script>
        <script src="/webjars/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    </body>
</html>

That HTML shows a layout template using Thymeleaf Layout. To making this layout working, make sure you have additional dependencies of Thymeleaf Layout Dialect that previously added in the first steps. All CSS and Javascript files put on that file and called once for all pages that use default.html as layout holder. Also, we call Bootstrap and JQuery on that file. Next, we create a view for the Product list with the name product.html then replace all codes to that file with this.

<!DOCTYPE HTML>
<html lang="en"
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="default">
    <head>
        <title>Product List</title>
    </head>
    <body>
        <div layout:fragment="content" class="row">
            <div class="col-xs-8 col-md-8">
                <h3>
                    <a href="/create" class="btn btn-primary"><span class="glyphicon glyphicon-plus-sign"></span> Product</a>
                </h3>
                <h2>Product List</h2>
                <div class="table-responsive">
                    <table class="table" id="product-table">
                        <thead>
                            <tr>
                                <th>Product Name</th>
                                <th>Product Desc</th>
                                <th>Product Price</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr th:each="product : ${products}">
                                <td><a th:text="${product.prodName}" th:href="@{'/show/' + ${product.id}}"></a></td>
                                <td th:text="${product.prodDesc}"></td>
                                <td th:text="${product.prodPrice}"></td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </body>
</html>

Next, create a view for creating a product form with the name create.html on Resources/templates folder then replace all codes with this.

<!DOCTYPE HTML>
<html lang="en"
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="default">
    <head>
        <title>Create Product</title>
    </head>
    <body>
        <div layout:fragment="content" class="row">
            <div class="col-xs-8 col-md-8">
                <h3>
                    <a href="/product" class="btn btn-lg btn-primary"><span class="glyphicon glyphicon-list"></span> Product</a>
                </h3>
                <h2>Create Product</h2>
                <form action="/save">
                    <div class="form-group">
                        <label for="email">Product Name:</label>
                        <input type="text" class="form-control" name="prodName" />
                    </div>
                    <div class="form-group">
                        <label for="email">Product Description</label>
                        <textarea class="form-control" name="prodDesc" cols="60" rows="3"></textarea>
                    </div>
                    <div class="form-group">
                        <label for="email">Product Price</label>
                        <input type="number" class="form-control" name="prodPrice" />
                    </div>
                    <div class="form-group">
                        <label for="email">Product Image URL:</label>
                        <input type="url" class="form-control" name="prodImage" />
                    </div>
                    <button type="submit" class="btn btn-success">Save</button>
                </form>
            </div>
        </div>
    </body>
</html>

Next, create a view for show product detail with the name show.html on Resources/templates folder then replace all codes with this.

<!DOCTYPE HTML>
<html lang="en"
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="default">
    <head>
        <title>Show Product</title>
    </head>
    <body>
        <div layout:fragment="content" class="row">
            <div class="col-xs-8 col-md-8">
                <h3>
                    <a href="/product" class="btn btn-primary"><span class="glyphicon glyphicon-list"></span> Product</a>
                </h3>
                <h2 th:text="${product.prodName}"></h2>
                <h2><img th:src="${product.prodImage}" width="200" /></h2>
                <dl class="list">
                    <dt>Product Description</dt>
                    <dd th:text="${product.prodDesc}"></dd>
                    <dt>Product Description</dt>
                    <dd th:text="${product.prodPrice}"></dd>
                </dl>
                <form action="/delete">
                    <input type="hidden" name="id" th:value="${product.id}" />
                    <h2><input type="submit" class="btn btn-danger" value="Delete" onclick="return confirm('Are you sure?');" />
                        <a th:href="@{'/edit/' + ${product.id}}" class="btn btn-warning">Edit</a></h2>
                </form>
            </div>
        </div>
    </body>
</html>

Next, create a view for edit product with the name edit.html on Resources/templates folder then replace all codes with this.

<!DOCTYPE HTML>
<html lang="en"
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="default">
    <head>
        <title>Edit Product</title>
    </head>
    <body>
        <div layout:fragment="content" class="row">
            <div class="col-xs-8 col-md-8">
                <h3>
                    <a href="/product" class="btn btn-lg btn-primary"><span class="glyphicon glyphicon-list"></span> Product</a>
                </h3>
                <h2>Edit Product</h2>
                <form action="/update">
                    <div class="form-group">
                        <label for="email">Product Name:</label>
                        <input type="text" class="form-control" name="prodName" th:value="${product.prodName}" />
                    </div>
                    <div class="form-group">
                        <label for="email">Product Description</label>
                        <textarea class="form-control" name="prodDesc" cols="60" rows="3" th:text="${product.prodDesc}"></textarea>
                    </div>
                    <div class="form-group">
                        <label for="email">Product Price</label>
                        <input type="number" class="form-control" name="prodPrice" th:value="${product.prodPrice}" />
                    </div>
                    <div class="form-group">
                        <label for="email">Product Image URL:</label>
                        <input type="url" class="form-control" name="prodImage" th:value="${product.prodImage}" />
                    </div>
                    <input type="hidden" name="id" th:value="${product.id}" />
                    <button type="submit" class="btn btn-success">Save</button>
                </form>
            </div>
        </div>
    </body>
</html>

Next, open and edit static HTML file Resources/static/index.html then replace all codes with this.

<!DOCTYPE HTML>
<html>
    <head>
        <title>Spring MVC Java Web App</title>
    </head>
    <body>
        <h2>Spring MVC Java Web App</h2>
        <p><a href="/product">Product List</a></p>
    </body>
</html>

This index.html is the first page that shows up on the browser after Web Application run. Next, add a little style by creating a new CSS folder inside the static folder then add a file style.css. Add these lines of CSS codes to that CSS file.

body {
  padding-top: 50px;
}
.starter-template {
  padding: 40px 15px;
  text-align: center;
}
Step #6: Run The Spring Boot Java Web App

To run the Spring Boot app inside Netbeans IDE, just click on the play button in the toolbar or right-click the project name in the Project panel then click run. It's the same as typing this command from the terminal.

./gradlew --configure-on-demand -x check bootRun

Here the full Spring Boot MVC Java web app looks like.





That it's, a quick way to create a Java web app using Spring Boot, Data, and MVC in just 5 steps. You can get the full working source code from our GitHub.

That just the basic. If you need more deep learning about Java and Spring Framework you can take the following cheap course:

Thanks!