Welcome To Fusebes - Dev & Programming Blog

Building Restful APIs with Kotlin, Spring Boot, Mysql, JPA and Hibernate
05
Mar
2021

Building Restful APIs with Kotlin, Spring Boot, MySQL , JPA and Hibernate

Kotlin has gained a lot of popularity in recent times due to its productivity features and a first class support in Android.

Owing to the increasing popularity of Kotlin, Spring framework 5 has also introduced a dedicated support for Kotlin in Spring applications.

In this article, You’ll learn how to build a Restful CRUD API with Kotlin and Spring Boot 2.x, which is based on Spring framework 5.

So Stay tuned!

What will we build?

In this blog post, we’ll build Restful APIs for a mini blog application. The blog has a list of Articles. We’ll write APIs for creating, retrieving, updating and deleting an Article. An Article has an id, a title and some content.

We’ll use MySQL as our data source and JPA & Hibernate to access the data from the database.

All right, Let’s now create the application.

Creating the Application

We’ll use Spring initializr web tool to bootstrap our application. Follow the steps below to generate the application :

  1. Go to http://start.spring.io
  2. Select Kotlin in the language section.
  3. Enter Artifact as kotlin-demo
  4. Add WebJPA, and MySQL dependencies.
  5. Click Generate to generate and download the project.
Kotlin Spring Boot Restful CRUD API Example

Once the project is generated, unzip it and import it into your favorite IDE. Here is the Project’s directory Structure for your reference.

Kotlin Spring Boot Restful CRUD API Example Directory Structure

Configure MySQL

We’ll need to configure MySQL database url, username, and password so that Spring Boot can create a Data source.

Open src/main/resources/application.properties file and add the following properties to it –

## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url = jdbc:mysql://localhost:3306/kotlin_demo_app?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false
spring.datasource.username = root
spring.datasource.password = root


## Hibernate Properties

# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect

# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update

Please don’t forget to change spring.datasource.username and spring.datasource.password as per your MySQL installation.

Note that, I’ve set spring.jpa.hibernate.ddl-auto property to update. This property updates the database schema whenever you create or modify the domain models in your application.

Creating the Domain Model

Let’s now create the Article domain entity. Create a new package called model inside com.example.kotlindemo package, and then create a new Kotlin file called Article.kt with the following contents –

package com.example.kotlindemo.model

import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id
import javax.validation.constraints.NotBlank

@Entity
data class Article (
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long = 0,

    @get: NotBlank
    val title: String = "",

    @get: NotBlank
    val content: String = ""
)

The Entity class is so small and concise, right? That’s because A Kotlin class doesn’t need getters and setters like Java. Moreover, I have used a data class here. A data class automatically generates equals()hashcode()toString() and copy() methods.

Note that, I’ve assigned a default value for all the fields in the Article class. This is needed because Hibernate requires an entity to have a no-arg constructor.

Assigning default values to all the member fields will let hibernate instantiate an Article without passing any argument. It Works because Kotlin supports Default Arguments 🙂

Creating the Repository

Let’s now create the repository for accessing the data from the database. First, create a package called repository inside com.example.kotlindemo package, and then create a Kotlin file named ArticleRepository.kt with the following contents –

package com.example.kotlindemo.repository

import com.example.kotlindemo.model.Article
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository

@Repository
interface ArticleRepository : JpaRepository<Article, Long>

That’s all we need to do here. Since we’ve extended ArticleRepository from JpaRepository interface, all the CRUD methods on Article entity is readily available to us. Spring boot automatically plugs-in a default implementation of JpaRepository called SimpleJpaRepository at runtime.

Creating the controller End-points

Finally, Let’s create the controller end-points for all the CRUD operations on Article entity.

First, create a new package called controller inside com.example.kotlindemo package and then create a new kotlin file called ArticleController.kt inside controller package with the following contents –

package com.example.kotlindemo.controller

import com.example.kotlindemo.model.Article
import com.example.kotlindemo.repository.ArticleRepository
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
import java.util.*
import javax.validation.Valid

@RestController
@RequestMapping("/api")
class ArticleController(private val articleRepository: ArticleRepository) {

    @GetMapping("/articles")
    fun getAllArticles(): List<Article> =
            articleRepository.findAll()


    @PostMapping("/articles")
    fun createNewArticle(@Valid @RequestBody article: Article): Article =
            articleRepository.save(article)


    @GetMapping("/articles/{id}")
    fun getArticleById(@PathVariable(value = "id") articleId: Long): ResponseEntity<Article> {
        return articleRepository.findById(articleId).map { article -> 
            ResponseEntity.ok(article)
        }.orElse(ResponseEntity.notFound().build())
    }

    @PutMapping("/articles/{id}")
    fun updateArticleById(@PathVariable(value = "id") articleId: Long,
                          @Valid @RequestBody newArticle: Article): ResponseEntity<Article> {

        return articleRepository.findById(articleId).map { existingArticle ->
            val updatedArticle: Article = existingArticle
                    .copy(title = newArticle.title, content = newArticle.content)
            ResponseEntity.ok().body(articleRepository.save(updatedArticle))
        }.orElse(ResponseEntity.notFound().build())

    }

    @DeleteMapping("/articles/{id}")
    fun deleteArticleById(@PathVariable(value = "id") articleId: Long): ResponseEntity<Void> {

        return articleRepository.findById(articleId).map { article  ->
            articleRepository.delete(article)
            ResponseEntity<Void>(HttpStatus.OK)
        }.orElse(ResponseEntity.notFound().build())

    }
}

The controller defines APIs for all the CRUD operations. I have used Kotlin’s functional style syntax in all the methods to make them short and concise.

Running the Application

You can run the application by typing the following command in the terminal –

mvn spring-boot:run

The application will start at Spring Boot’s default port 8080.

Exploring the Rest APIs

1. POST /api/articles – Create an Article

curl -i -H "Content-Type: application/json" -X POST \
-d '{"title": "How to learn Spring framework", "content": "Resources to learn Spring framework"}' \
http://localhost:8080/api/articles

# Output
HTTP/1.1 200 
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 06 Oct 2017 03:25:59 GMT

{"id":1,"title":"How to learn Spring framework","content":"Resources to learn Spring framework"}

2. GET /api/articles – Get all Articles

curl -i -H 'Accept: application/json' http://localhost:8080/api/articles

# Output
HTTP/1.1 200 
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 06 Oct 2017 03:25:29 GMT

[{"id":1,"title":"How to learn Spring framework","content":"Resources to learn Spring framework"}]

3. Get /api/articles/{id} – Get an Article by id

curl -i -H 'Accept: application/json' http://localhost:8080/api/articles/1

# Output
HTTP/1.1 200 
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 06 Oct 2017 03:27:51 GMT

{"id":1,"title":"How to learn Spring framework","content":"Resources to learn Spring framework"}

4. PUT /api/articles/{id} – Update an Article

curl -i -H "Content-Type: application/json" -X PUT \
-d '{"title": "Learning Spring Boot", "content": "Some resources to learn Spring Boot"}' \
http://localhost:8080/api/articles/1

# Output
HTTP/1.1 200 
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 06 Oct 2017 03:33:15 GMT

{"id":1,"title":"Learning Spring Boot","content":"Some resources to learn Spring Boot"}

5. DELETE /api/articles/{id} – Delete an Article

curl -i -X DELETE http://localhost:8080/api/articles/1

# Output
HTTP/1.1 200 
Content-Length: 0
Date: Fri, 06 Oct 2017 03:34:22 GMT

Conclusion

That’s all folks! In this article, You learned how to use Kotlin with Spring Boot for building restful web services.

You can find the entire code for the application that we built in this article in my github repository. Consider giving a star on github if you find the project useful.

Thank you for reading folks! See you next time 🙂

Spring Boot Actuator metrics monitoring with Prometheus and Grafana
03
Mar
2021

Spring Boot Actuator metrics monitoring with Prometheus and Grafana

Welcome to the second part of the Spring Boot Actuator tutorial series. In the first part, you learned what spring-boot-actuator module does, how to configure it in a spring boot application, and how to interact with various actuator endpoints.

In this article, you’ll learn how to integrate spring boot actuator with a monitoring system called Prometheus and a graphing solution called Grafana.

At the end of this article, you’ll have a Prometheus as well as a Grafana dashboard setup in your local machine where you’ll be able to visualize and monitor all the metrics generated from the Spring Boot application.

Prometheus

Prometheus is an open-source monitoring system that was originally built by SoundCloud. It consists of the following core components –

  • A data scraper that pulls metrics data over HTTP periodically at a configured interval.
  • time-series database to store all the metrics data.
  • A simple user interface where you can visualize, query, and monitor all the metrics.

Grafana

Grafana allows you to bring data from various data sources like Elasticsearch, Prometheus, Graphite, InfluxDB etc, and visualize them with beautiful graphs.

It also lets you set alert rules based on your metrics data. When an alert changes state, it can notify you over email, slack, or various other channels.

Note that, Prometheus dashboard also has simple graphs. But Grafana’s graphs are way better. That’s why, in this post, we’ll integrate Grafana with Prometheus to import and visualize our metrics data.

Adding Micrometer Prometheus Registry to your Spring Boot application

Spring Boot uses Micrometer, an application metrics facade to integrate actuator metrics with external monitoring systems.

It supports several monitoring systems like Netflix Atlas, AWS Cloudwatch, Datadog, InfluxData, SignalFx, Graphite, Wavefront, Prometheus etc.

To integrate actuator with Prometheus, you need to add the micrometer-registry-prometheus dependency –

<!-- Micrometer Prometheus registry  -->
<dependency>
	<groupId>io.micrometer</groupId>
	<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

Once you add the above dependency, Spring Boot will automatically configure a PrometheusMeterRegistry and a CollectorRegistry to collect and export metrics data in a format that can be scraped by a Prometheus server.

All the application metrics data are made available at an actuator endpoint called /prometheus. The Prometheus server can scrape this endpoint to get metrics data periodically.

Exploring Spring Boot Actuator’s /prometheus Endpoint

Let’s explore the prometheus endpoint that is exposed by Spring Boot when micrometer-registry-prometheus dependency is available on the classpath.

First of all, you’ll start seeing the prometheus endpoint on the actuator endpoint-discovery page (http://localhost:8080/actuator) –

Spring Boot Actuator Prometheus Endpoint

The prometheus endpoint exposes metrics data in a format that can be scraped by a Prometheus server. You can see the exposed metrics data by navigating to the prometheus endpoint (http://localhost:8080/actuator/prometheus) –

# HELP jvm_buffer_memory_used_bytes An estimate of the memory that the Java virtual machine is using for this buffer pool
# TYPE jvm_buffer_memory_used_bytes gauge
jvm_buffer_memory_used_bytes{id="direct",} 81920.0
jvm_buffer_memory_used_bytes{id="mapped",} 0.0
# HELP jvm_threads_live The current number of live threads including both daemon and non-daemon threads
# TYPE jvm_threads_live gauge
jvm_threads_live 23.0
# HELP tomcat_global_received_bytes_total  
# TYPE tomcat_global_received_bytes_total counter
tomcat_global_received_bytes_total{name="http-nio-8080",} 0.0
# HELP jvm_gc_pause_seconds Time spent in GC pause
# TYPE jvm_gc_pause_seconds summary
jvm_gc_pause_seconds_count{action="end of minor GC",cause="Allocation Failure",} 7.0
jvm_gc_pause_seconds_sum{action="end of minor GC",cause="Allocation Failure",} 0.232
jvm_gc_pause_seconds_count{action="end of minor GC",cause="Metadata GC Threshold",} 1.0
jvm_gc_pause_seconds_sum{action="end of minor GC",cause="Metadata GC Threshold",} 0.01
jvm_gc_pause_seconds_count{action="end of major GC",cause="Metadata GC Threshold",} 1.0
jvm_gc_pause_seconds_sum{action="end of major GC",cause="Metadata GC Threshold",} 0.302
# HELP jvm_gc_pause_seconds_max Time spent in GC pause
# TYPE jvm_gc_pause_seconds_max gauge
jvm_gc_pause_seconds_max{action="end of minor GC",cause="Allocation Failure",} 0.0
jvm_gc_pause_seconds_max{action="end of minor GC",cause="Metadata GC Threshold",} 0.0
jvm_gc_pause_seconds_max{action="end of major GC",cause="Metadata GC Threshold",} 0.0
# HELP jvm_gc_live_data_size_bytes Size of old generation memory pool after a full GC
# TYPE jvm_gc_live_data_size_bytes gauge
jvm_gc_live_data_size_bytes 5.0657472E7

## More data ...... (Omitted for brevity)

Downloading and Running Prometheus using Docker

1. Downloading Prometheus

You can download the Prometheus docker image using docker pull command like so –

$ docker pull prom/prometheus

Once the image is downloaded, you can type docker image ls command to view the list of images present locally –

$ docker image ls
REPOSITORY                                   TAG                 IMAGE ID            CREATED             SIZE
prom/prometheus                              latest              b82ef1f3aa07        5 days ago          119MB

2. Prometheus Configuration (prometheus.yml)

Next, We need to configure Prometheus to scrape metrics data from Spring Boot Actuator’s /prometheus endpoint.

Create a new file called prometheus.yml with the following configurations –

# my global config
global:
  scrape_interval:     15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  # - "first_rules.yml"
  # - "second_rules.yml"

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: 'prometheus'
    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.
    static_configs:
    - targets: ['127.0.0.1:9090']

  - job_name: 'spring-actuator'
    metrics_path: '/actuator/prometheus'
    scrape_interval: 5s
    static_configs:
    - targets: ['HOST_IP:8080']

The above configuration file is an extension of the basic configuration file available in the Prometheus documentation.

The most important stuff to note in the above configuration file is the spring-actuator job inside scrape_configs section.

The metrics_path is the path of the Actuator’s prometheus endpoint. The targets section contains the HOST and PORT of your Spring Boot application.

Please make sure to replace the HOST_IP with the IP address of the machine where your Spring Boot application is running. Note that, localhost won’t work here because we’ll be connecting to the HOST machine from the docker container. You must specify the network IP address.

3. Running Prometheus using Docker

Finally, Let’s run Prometheus using Docker. Type the following command to start a Prometheus server in the background –

$ docker run -d --name=prometheus -p 9090:9090 -v <PATH_TO_prometheus.yml_FILE>:/etc/prometheus/prometheus.yml prom/prometheus --config.file=/etc/prometheus/prometheus.yml

Please make sure to replace the <PATH_TO_prometheus.yml_FILE> with the PATH where you have stored the Prometheus configuration file.

After running the above command, docker will start the Prometheus server inside a container. You can see the list of all the containers with the following command –

$ docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
e036eb20b8ad        prom/prometheus     "/bin/prometheus --c…"   4 minutes ago       Up 4 minutes        0.0.0.0:9090->9090/tcp   prometheus

4. Visualizing Spring Boot Metrics from Prometheus dashboard

That’s it! You can now navigate to http://localhost:9090 to explore the Prometheus dashboard.

You can enter a Prometheus query expression inside the Expression text field and visualize all the metrics for that query.

Following are some Prometheus graphs for our Spring Boot application’s metrics –

  • System’s CPU usage –
Spring Boot Actuator Metrics Dashboard Prometheus
  • Response latency of a slow API –
Spring Boot Actuator Prometheus Dashboard Graph Example

You can check out the official Prometheus documentation to learn more about Prometheus Query Expressions.

Downloading and running Grafana using Docker

Type the following command to download and run Grafana using Docker –

$ docker run -d --name=grafana -p 3000:3000 grafana/grafana 

The above command will start Grafana inside a Docker container and make it available on port 3000 on the Host machine.

You can type docker container ls to see the list of Docker containers –

$ docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED                  STATUS              PORTS                    NAMES
cf9196b30d0d        grafana/grafana     "/run.sh"                Less than a second ago   Up 5 seconds        0.0.0.0:3000->3000/tcp   grafana
e036eb20b8ad        prom/prometheus     "/bin/prometheus --c…"   16 minutes ago           Up 16 minutes       0.0.0.0:9090->9090/tcp   prometheus

That’s it! You can now navigate to http://localhost:3000 and log in to Grafana with the default username admin and password admin.

Configuring Grafana to import metrics data from Prometheus

Follow the steps below to import metrics from Prometheus and visualize them on Grafana:

1. Add the Prometheus data source in Grafana

Spring Boot Actuator Prometheus Grafana Dashboard

2. Create a new Dashboard with a Graph

Spring Boot Actuator Grafana Dashboard Create Graph

3. Add a Prometheus Query expression in Grafana’s query editor

Spring Boot Actuator Grafana Dashboard Prometheus Metrics Graph

4. Visualize metrics from Grafana’s dashboard

Spring Boot Actuator Grafana Dashboard Visualize Prometheus metrics graph

Read the First Part: Spring Boot Actuator: Health check, Auditing, Metrics gathering and Monitoring

More Learning Resources

Microservices Architecture
14
May
2021

Microservices Architecture

Microservices are defined as a self-regulating, and independent codebase that can be written and maintained even by a small team of developers. Microservices Architecture consists of such loosely coupled services with each service responsible for the execution of its associated business logic. 

The services are separated from each other based on the nature of their domains and belong to a mini-microservice pool. Enterprise mobile app developers leverage the capabilities of this architecture especially for complex applications. 

Microservices Architecture allows developers to release versions of software thanks to sophisticated automation of software building, testing, and deployment – something that acts as a prime differentiation point between Microservices and Monolithic architecture.

Microservices Architecture

Benefits

  • Since the services are bifurcated into pools, the architecture design pattern makes the system highly fault-tolerant. In other words, the whole software won’t collapse on its head even if some microservices cease to function. 
  • An enterprise mobile app development company working on such an architecture for clients can deploy multiple programming languages to build different microservices for their specific purpose. Therefore the technology stack can be kept updated with the latest upgrades in computing. 
  • This architecture is a perfect fit for applications that need to scale. Since the services are already independent of each other, they can scale individually rather than overloading the entire system with the need to expand. 
  • Services can be integrated into any application depending upon the scope of work. 

Potential Drawbacks 

  • Since each service is unique in its ability to contribute to the whole codebase, it could be challenging for an enterprise mobile application development company to interlink all and operate so many distinctive services seamlessly. 
  • Developers must define a standard protocol for all services to adhere to. It is important to do so, as the decentralized approach towards coding microservices in multiple languages can pose serious issues while debugging. 
  • Each microservice with its limited environment is responsible to maintain the integrity of the data. It is up to the architects of such a system to come up with a universally consistent data integrity protocol, wherever possible. 
  • You definitely need the best of breed professionals to design such a system for you as the technology stack keeps changing. 

Ideal For

Use Microservices Architecture for apps in which a specific segment will be used heavily than the others and would need a sporadic burst of scaling. Instead of a standalone application you may also deploy this for a service that provides functionality to other applications of the system. 

Spring Boot File Upload / Download with JPA, Hibernate, and MySQL database
03
Mar
2021

Spring Boot File Upload / Download with JPA, Hibernate and MySQL database

In this article, you’ll learn how to upload and download files in a Restful spring boot web service. The files will be stored in MySQL database.

This article is a continuation of an earlier article where I’ve shown how to upload files and store them in the local filesystem.

We’ll reuse most of the code and concepts described in the last article. So I highly recommend you to go through that before reading this one.

Following is the directory structure of the complete application for your reference –

Spring Boot File Upload Download JPA, Hibernate, MySQL database example.

JPA and MySQL dependencies

Since we’ll be storing files in MySQL database, we’ll need JPA and MySQL dependencies along with Web dependency. So make sure that your pom file contains the following dependencies –

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-data-jpa</artifactId>
	</dependency>

	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<scope>runtime</scope>
	</dependency>

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
</dependencies>

If you’re building the project from scratch, you can generate the project skeleton from Spring Initialzr website

Configuring the Database and Multipart File properties

Next, we need to configure the MySQL database url, username, and password. You can configure that in the src/main/resources/application.properties file –

## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url= jdbc:mysql://localhost:3306/file_demo?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false
spring.datasource.username= root
spring.datasource.password= pass

## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto = update

## Hibernate Logging
logging.level.org.hibernate.SQL= DEBUG


## MULTIPART (MultipartProperties)
# Enable multipart uploads
spring.servlet.multipart.enabled=true
# Threshold after which files are written to disk.
spring.servlet.multipart.file-size-threshold=2KB
# Max file size.
spring.servlet.multipart.max-file-size=200MB
# Max Request Size
spring.servlet.multipart.max-request-size=215MB

The above properties file also has Multipart file properties. You can make changes to these properties as per your requirements.

DBFile model

Let’s create a DBFile entity to model the file attributes that will be stored in the database –

package com.example.filedemo.model;

import org.hibernate.annotations.GenericGenerator;

import javax.persistence.*;

@Entity
@Table(name = "files")
public class DBFile {
    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    private String id;

    private String fileName;

    private String fileType;

    @Lob
    private byte[] data;

    public DBFile() {

    }

    public DBFile(String fileName, String fileType, byte[] data) {
        this.fileName = fileName;
        this.fileType = fileType;
        this.data = data;
    }

    // Getters and Setters (Omitted for brevity)
}

Note that, the file’s contents will be stored as a byte array in the database.

DBFileRepository

Next, we need to create a repository to save files in the database and retrieve them back –

package com.example.filedemo.repository;

import com.example.filedemo.model.DBFile;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface DBFileRepository extends JpaRepository<DBFile, String> {

}

DBFileStorageService

The following DBFileStorageService contains methods to store and retrieve files to/from the database –

package com.example.filedemo.service;

import com.example.filedemo.exception.FileStorageException;
import com.example.filedemo.exception.MyFileNotFoundException;
import com.example.filedemo.model.DBFile;
import com.example.filedemo.repository.DBFileRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;

@Service
public class DBFileStorageService {

    @Autowired
    private DBFileRepository dbFileRepository;

    public DBFile storeFile(MultipartFile file) {
        // Normalize file name
        String fileName = StringUtils.cleanPath(file.getOriginalFilename());

        try {
            // Check if the file's name contains invalid characters
            if(fileName.contains("..")) {
                throw new FileStorageException("Sorry! Filename contains invalid path sequence " + fileName);
            }

            DBFile dbFile = new DBFile(fileName, file.getContentType(), file.getBytes());

            return dbFileRepository.save(dbFile);
        } catch (IOException ex) {
            throw new FileStorageException("Could not store file " + fileName + ". Please try again!", ex);
        }
    }

    public DBFile getFile(String fileId) {
        return dbFileRepository.findById(fileId)
                .orElseThrow(() -> new MyFileNotFoundException("File not found with id " + fileId));
    }
}

FileController (File upload/download REST APIs)

Finally, following are the Rest APIs to upload and download files –

package com.example.filedemo.controller;

import com.example.filedemo.model.DBFile;
import com.example.filedemo.payload.UploadFileResponse;
import com.example.filedemo.service.DBFileStorageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@RestController
public class FileController {

    private static final Logger logger = LoggerFactory.getLogger(FileController.class);

    @Autowired
    private DBFileStorageService dbFileStorageService;

    @PostMapping("/uploadFile")
    public UploadFileResponse uploadFile(@RequestParam("file") MultipartFile file) {
        DBFile dbFile = dbFileStorageService.storeFile(file);

        String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
                .path("/downloadFile/")
                .path(dbFile.getId())
                .toUriString();

        return new UploadFileResponse(dbFile.getFileName(), fileDownloadUri,
                file.getContentType(), file.getSize());
    }

    @PostMapping("/uploadMultipleFiles")
    public List<UploadFileResponse> uploadMultipleFiles(@RequestParam("files") MultipartFile[] files) {
        return Arrays.asList(files)
                .stream()
                .map(file -> uploadFile(file))
                .collect(Collectors.toList());
    }

    @GetMapping("/downloadFile/{fileId}")
    public ResponseEntity<Resource> downloadFile(@PathVariable String fileId) {
        // Load file from database
        DBFile dbFile = dbFileStorageService.getFile(fileId);

        return ResponseEntity.ok()
                .contentType(MediaType.parseMediaType(dbFile.getFileType()))
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + dbFile.getFileName() + "\"")
                .body(new ByteArrayResource(dbFile.getData()));
    }

}

Results

I’ll be reusing the complete front-end code that I demonstrated in the first part of this article. You should check out the first article to learn more about the front-end code.

Once you have the front-end code in place, type the following command to run the application –

mvn spring-boot:run

Here is a screenshot of the final app –

Spring Boot File Upload Download with JPA, Hibernate and MySQL database demo

That’s all for now. Thanks for reading!

Deploying a containerized Go app on Kubernetes
06
Feb
2021

Deploying a containerized Go app on Kubernetes

Introduction

Kubernetes is an open-source container orchestrator built by Google that helps you run, manage, and scale containerized applications on the cloud.

It has everything to automate the deployment, scaling, and management of modern applications. Some notable features of Kubernetes are:

  • Horizontal auto-scaling
  • Service discovery and Load balancing
  • Rolling updates with zero downtime
  • Self-healing mechanisms (using health-checks)
  • Secret and configuration management

All the major cloud providers (Google Cloud, AWS, Azure, DigitalOcean, etc) have managed Kubernetes platforms. This means that you can easily switch between different cloud platforms without making any changes in your architecture.

In this article, You’ll learn how to deploy, manage, and scale a simple Go web app on Kubernetes.

We’ll deploy the app on a local kubernetes cluster created using minikube. Minikube is a tool that lets you set up a single-node Kubernetes cluster inside a VM on your local machine. It’s great for learning and playing with Kubernetes.

Building a sample web application in Go

Let’s build a simple Go web app to deploy on Kubernetes. Fire up your terminal and create a new folder for the project:

$ mkdir go-kubernetes

Next, Initialize Go modules by running the following command

$ cd go-kubernetes
$ go mod init github.com/changeit/go-kubernetes # Change the module path as per your Github username

Now, Create a file named main.go and copy the following code –

package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/gorilla/mux"
)

func handler(w http.ResponseWriter, r *http.Request) {
	query := r.URL.Query()
	name := query.Get("name")
	if name == "" {
		name = "Guest"
	}
	log.Printf("Received request for %s\n", name)
	w.Write([]byte(fmt.Sprintf("Hello, %s\n", name)))
}

func healthHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
}

func readinessHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
}

func main() {
	// Create Server and Route Handlers
	r := mux.NewRouter()

	r.HandleFunc("/", handler)
	r.HandleFunc("/health", healthHandler)
	r.HandleFunc("/readiness", readinessHandler)

	srv := &http.Server{
		Handler:      r,
		Addr:         ":8080",
		ReadTimeout:  10 * time.Second,
		WriteTimeout: 10 * time.Second,
	}

	// Start Server
	go func() {
		log.Println("Starting Server")
		if err := srv.ListenAndServe(); err != nil {
			log.Fatal(err)
		}
	}()

	// Graceful Shutdown
	waitForShutdown(srv)
}

func waitForShutdown(srv *http.Server) {
	interruptChan := make(chan os.Signal, 1)
	signal.Notify(interruptChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)

	// Block until we receive our signal.
	<-interruptChan

	// Create a deadline to wait for.
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()
	srv.Shutdown(ctx)

	log.Println("Shutting down")
	os.Exit(0)
}

The app uses gorilla mux library for routing. It also has /health and /readiness endpoints apart from the / endpoint. You’ll find out what is the use of these endpoints in the later section.

Let’s now build and run the app locally:

$ go build
$ ./go-kubernetes
2019/07/27 11:51:58 Starting Server

$ curl localhost:8080?name=Rajeev
Hello, Rajeev

Dockerizing the Go application

To deploy our app on Kubernetes, we need to first containerize it. Create a file named Dockerfile inside the project’s folder and add the following configurations in the Dockerfile.

# Dockerfile References: https://docs.docker.com/engine/reference/builder/

# Start from the latest golang base image
FROM golang:latest as builder

# Add Maintainer Info
LABEL maintainer="Rajeev Singh <rajeevhub@gmail.com>"

# Set the Current Working Directory inside the container
WORKDIR /app

# Copy go mod and sum files
COPY go.mod go.sum ./

# Download all dependancies. Dependencies will be cached if the go.mod and go.sum files are not changed
RUN go mod download

# Copy the source from the current directory to the Working Directory inside the container
COPY . .

# Build the Go app
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .


######## Start a new stage from scratch #######
FROM alpine:latest  

RUN apk --no-cache add ca-certificates

WORKDIR /root/

# Copy the Pre-built binary file from the previous stage
COPY --from=builder /app/main .

# Expose port 8080 to the outside world
EXPOSE 8080

# Command to run the executable
CMD ["./main"] 

I’m not gonna go into the details of the Dockerfile here. Please check out the article Building Docker Containers for Go Applications to learn more.

Building and pushing the docker image to docker hub

Let’s build and push the docker image of our Go app on docker hub so that we can later use this image while deploying the app on Kubernetes –

# Build the docker image
$ docker build -t go-kubernetes .

# Tag the image
$ docker tag go-kubernetes modulename/go-hello-world:1.0.0

# Login to docker with your docker Id
$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don\'t have a Docker ID, head over to https://hub.docker.com to create one.
Username (username): password
Password:
Login Succeeded

# Push the image to docker hub
$ docker push modulename/go-hello-world:1.0.0

Creating a Kubernetes deployment

All right! Let’s now create a Kubernetes deployment for our app. Deployments are a declarative way to instruct Kubernetes how to create and update instances of your application. A deployment consists of a set of identical, indistinguishable Pods.

Pod represents a unit of deployment, i.e. a single instance of your application in Kubernetes, which might consist of either a single container or a small number of containers that are tightly coupled and that share resources.

When it comes to managing Pods, deployments abstract away the low-level details like what node is the Pod running on. Pods are tied to the lifetime of the node. So when the node dies, so does the Pod. It’s the job of the deployment to ensure that the current number of Pods equals the desired number of Pods.

We specify the details of the number of Pods, what containers to run inside the Pod, how to check if the Pod is healthy or not, in a so-called manifest file. It’s a simple yaml file with a bunch of configurations containing the desired state of our application.

k8s-deployment.yml

---
apiVersion: apps/v1
kind: Deployment                 # Type of Kubernetes resource
metadata:
  name: go-hello-world           # Name of the Kubernetes resource
spec:
  replicas: 3                    # Number of pods to run at any given time
  selector:
    matchLabels:
      app: go-hello-world        # This deployment applies to any Pods matching the specified label
  template:                      # This deployment will create a set of pods using the configurations in this template
    metadata:
      labels:                    # The labels that will be applied to all of the pods in this deployment
        app: go-hello-world 
    spec:                        # Spec for the container which will run in the Pod
      containers:
      - name: go-hello-world
        image: modulename/go-hello-world:1.0.0 
        imagePullPolicy: IfNotPresent
        ports:
          - containerPort: 8080  # Should match the port number that the Go application listens on
        livenessProbe:           # To check the health of the Pod
          httpGet:
            path: /health
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 5
          periodSeconds: 15
          timeoutSeconds: 5
        readinessProbe:          # To check if the Pod is ready to serve traffic or not
          httpGet:
            path: /readiness
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 5
          timeoutSeconds: 1    

I’ve added comments alongside each configuration in the above deployment manifest file. But I want to talk more about some of them.

Notice the configuration replicas: 3 in the above file. It instructs Kubernetes to run 3 instances of our application at any given time. If an instance dies, Kubernetes automatically spins up another instance.

Let’s also talk about the livenessProbe and readinessProbe. Sometimes a container on a pod can be running but the application inside of the container might be malfunctioning. For instance, if your code was deadlocked.

Kubernetes has built-in support to make sure that your application is running correctly with user implemented application health and readiness checks.

Readiness probes indicate when an application is ready to serve traffic. If a readiness check fails then the container will be marked as not ready and will be removed from any load balancers.

Liveness probes indicate a container is alive. If a liveness probe fails multiple times, then the container will be restarted.

Starting a local Kubernetes cluster using Minikube and deploying the app

You’ll need to install and set up kubectl (Kubernetes command-line tool) and Minikube to proceed further. Please follow the instructions on the official Kubernetes website to install kubectl and minikube.

Once the installation is complete, type the following command to start a Kubernetes cluster:

$ minikube start

Let’s now deploy our app to the minikube cluster by applying the deployment manifest using kubectl.

$ kubectl apply -f k8s-deployment.yml
deployment.apps/go-hello-world created

That’s it! The deployment is created. You can get the deployments like this:

$ kubectl get deployments
NAME             READY   UP-TO-DATE   AVAILABLE   AGE
go-hello-world   3/3     3            3           25s

You can type the following command to get the pods in the cluster:

$ kubectl get pods
NAME                              READY   STATUS    RESTARTS   AGE
go-hello-world-69b45499fb-7fh87   1/1     Running   0          37s
go-hello-world-69b45499fb-rt2xj   1/1     Running   0          37s
go-hello-world-69b45499fb-xjmlq   1/1     Running   0          37s

Pods are allocated a private IP address by default and cannot be reached outside of the cluster. You can use the kubectl port-forward command to map a local port to a port inside the pod like this:

$ kubectl port-forward go-hello-world-69b45499fb-7fh87 8080:8080
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080

You can now interact with the Pod on the forwarded port:

$ curl localhost:8080
Hello, Guest

$ curl localhost:8080?name=Rajeev
Hello, Rajeev

You can also stream the Pod logs by typing the following command:

$ kubectl logs -f go-hello-world-69b45499fb-7fh87
2019/07/27 06:12:09 Starting Server
2019/07/27 06:15:42 Received request for Guest
2019/07/27 06:16:02 Received request for Rajeev

Creating a Kubernetes Service

The port-forward command is good for testing the pods directly. But in production, you would want to expose the pod using services.

Pods can be restarted for all kinds of reasons like failed liveliness checks, readiness checks or they can be killed if the node they are running on dies.

Instead of relying on the Pods IP addresses which change, Kubernetes provides services as stable endpoint for pods. The pods that the service exposes are based on a set of labels. If Pods have the correct labels, they are automatically picked up and exposed by our services.

The level of access the service provides to the set of pods depends on the service type which can be:

  • ClusterIP: Internal only.
  • NodePort: Gives each node an external IP that’s accessible from outside the cluster and also opens a Port. A kube-proxy component that runs on each node of the Kubernetes cluster listens for incoming traffic on the port and forwards them to the selected pods in a round-robin fashion.
  • LoadBalancer: Adds a load balancer from the cloud provider which forwards traffic from the service to the nodes within it.

Let’s expose our Pods by creating a service. Add the following configurations in the k8s-deployment.yml file:

---
apiVersion: v1
kind: Service                    # Type of kubernetes resource
metadata:
  name: go-hello-world-service   # Name of the resource
spec:
  type: NodePort                 # A port is opened on each node in your cluster via Kube proxy.
  ports:                         # Take incoming HTTP requests on port 9090 and forward them to the targetPort of 8080
  - name: http
    port: 9090
    targetPort: 8080
  selector:
    app: go-hello-world         # Map any pod with label `app=go-hello-world` to this service

Let’s now apply the above configurations by typing the following command:

$ kubectl apply -f k8s-deployment.yml
deployment.apps/go-hello-world unchanged
service/go-hello-world-service created

A service is created for exposing the Pods. You can get the list of services in the kubernetes cluster like this:

$ kubectl get services
NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
go-hello-world-service   NodePort    10.111.51.170   <none>        9090:32550/TCP   35s
kubernetes               ClusterIP   10.96.0.1       <none>        443/TCP          13h

Type the following command to get the URL for the service in the minikube cluster:

$ minikube service go-hello-world-service --url
http://192.168.99.100:32550

That’s all! You can now interact with the service on the above URL:

$ curl http://192.168.99.100:32550
Hello, Guest

$ curl http://192.168.99.100:32550?name=Rajeev
Hello, Rajeev

Scaling a Kubernetes deployment

You can scale the number of Pods by increasing the number of replicas in the kubernetes deployment manifest and applying the changes using kubectl.

You can also use kubectl scale command to increase the number of pods:

$ kubectl scale --replicas=4 deployment/go-hello-world
deployment.extensions/go-hello-world scaled

$ kubectl get pods
NAME                              READY   STATUS    RESTARTS   AGE
go-hello-world-69b45499fb-7fh87   1/1     Running   0          112m
go-hello-world-69b45499fb-hzb6v   1/1     Running   0          10s
go-hello-world-69b45499fb-rt2xj   1/1     Running   0          112m
go-hello-world-69b45499fb-xjmlq   1/1     Running   0          112m

Deleting Kubernetes resources

Deleting a Pod

$ kubectl delete pod go-hello-world-69b45499fb-7fh87
pod "go-hello-world-69b45499fb-7fh87" deleted

Deleting a Service

$ kubectl delete service go-hello-world-service
service "go-hello-world-service" deleted

Deleting a Deployment

$ kubectl delete deployment go-hello-world
deployment.extensions "go-hello-world" deleted

Stopping and Deleting the Minikube cluster

Stopping the minikube kubernetes cluster

$ minikube stop

Deleting the minikube kubernetes cluster

$ minikube delete

Conclusion

That’s all in this article. You can find the complete code in the following Github repository.

As always, thanks for reading. I hope you found the article useful. Let me know your thoughts in the comment section below.

How to read a File in Java
03
Mar
2021

How to read a File in Java

In this article, you’ll learn how to read a text file or binary (image) file in Java using various classes and utility methods provided by Java like:

BufferedReaderLineNumberReader
Files.readAllLinesFiles.lines
BufferedInputStreamFiles.readAllBytes, etc.

Let’s look at each of the different ways of reading a file in Java with the help of examples.

Java read file using BufferedReader

BufferedReader is a simple and performant way of reading text files in Java. It reads text from a character-input stream. It buffers characters to provide efficient reading.

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class BufferedReaderExample {
    public static void main(String[] args) {
        Path filePath = Paths.get("demo.txt");
        Charset charset = StandardCharsets.UTF_8;

        try (BufferedReader bufferedReader = Files.newBufferedReader(filePath, charset)) {
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException ex) {
            System.out.format("I/O error: %s%n", ex);
        }
    }
}

Java read file line by line using Files.readAllLines()

Files.readAllLines() is a utility method of the Java NIO’s Files class that reads all the lines of a file and returns a List<String> containing each line. It internally uses BufferedReader to read the file.

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

public class FilesReadAllLinesExample {
    public static void main(String[] args) {
        Path filePath = Paths.get("demo.txt");
        Charset charset = StandardCharsets.UTF_8;
        try {
            List<String> lines = Files.readAllLines(filePath, charset);
            for(String line: lines) {
                System.out.println(line);
            }
        } catch (IOException ex) {
            System.out.format("I/O error: %s%n", ex);
        }
    }
}

Java read file line by line using Files.lines()

Files.lines() method reads all the lines from a file as a Stream. You can use Stream API methods like forEachmap to work with each line of the file.

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class FilesLinesExample {
    public static void main(String[] args) {
        Path filePath = Paths.get("demo.txt");
        Charset charset = StandardCharsets.UTF_8;

        try {

            Files.lines(filePath, charset)
                    .forEach(System.out::println);

        } catch (IOException ex) {
            System.out.format("I/O error: %s%n", ex);
        }
    }
}

Java read file line by line using LineNumberReader

LineNumberReader is a buffered character-stream reader that keeps track of line numbers. You can use this class to read a text file line by line.

import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class LineNumberReaderExample {
    public static void main(String[] args) {
        Path filePath = Paths.get("demo.txt");
        Charset charset = StandardCharsets.UTF_8;

        try(BufferedReader bufferedReader = Files.newBufferedReader(filePath, charset);
            LineNumberReader lineNumberReader = new LineNumberReader(bufferedReader)) {

            String line;
            while ((line = lineNumberReader.readLine()) != null) {
                System.out.format("Line %d: %s%n", lineNumberReader.getLineNumber(), line);
            }
        } catch (IOException ex) {
            System.out.format("I/O error: %s%n", ex);
        }
    }
}

Java read binary file (image file) using BufferedInputStream

All the examples presented in this article so far read textual data from a character-input stream. If you’re reading a binary data such as an image file then you need to use a byte-input stream.

BufferedInputStream lets you read raw stream of bytes. It also buffers the input for improving performance

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;

public class BufferedInputStreamImageCopyExample {
    public static void main(String[] args) {
        try(InputStream inputStream = Files.newInputStream(Paths.get("sample.jpg"));
            BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);

            OutputStream outputStream = Files.newOutputStream(Paths.get("sample-copy.jpg"));
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream)) {

            byte[] buffer = new byte[4096];
            int numBytes;
            while ((numBytes = bufferedInputStream.read(buffer)) != -1) {
                bufferedOutputStream.write(buffer, 0, numBytes);
            }
        } catch (IOException ex) {
            System.out.format("I/O error: %s%n", ex);
        }
    }
}

Java read file into []byte using Files.readAllBytes()

If you want to read the entire contents of a file in a byte array then you can use the Files.readAllBytes() method.

import com.sun.org.apache.xpath.internal.operations.String;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class FilesReadAllBytesExample {
    public static void main(String[] args) {
        try {
            byte[] data = Files.readAllBytes(Paths.get("demo.txt"));

            // Use byte data
        } catch (IOException ex) {
            System.out.format("I/O error: %s%n", ex);
        }

    }
}
JPA / Hibernate ElementCollection Example with Spring Boot
03
Mar
2021

JPA / Hibernate ElementCollection Example with Spring Boot

In this article, You’ll learn how to map a collection of basic as well as embeddable types using JPA’s @ElementCollection and @CollectionTable annotations.

Let’s say that the users of your application can have multiple phone numbers and addresses. To map this requirement into the database schema, you need to create separate tables for storing the phone numbers and addresses –

Hibernate Spring Boot JPA @ElementCollection example table structure

Both the tables user_phone_numbers and user_addresses contain a foreign key to the users table.

You can implement such relationship at the object level using JPA’s one-to-many mapping. But for basic and embeddable types like the one in the above schema, JPA has a simple solution in the form of ElementCollection.

Let’s create a project from scratch and learn how to use an ElementCollection to map the above schema in your application using hibernate.

Creating the Application

If you have Spring Boot CLI installed, then simply type the following command in your terminal to generate the application –

spring init -n=jpa-element-collection-demo -d=web,jpa,mysql --package-name=com.example.jpa jpa-element-collection-demo

Alternatively, You can use Spring Initializr web app to generate the application by following the instructions below –

  1. Open http://start.spring.io
  2. Enter Artifact as “jpa-element-collection-demo”
  3. Click Options dropdown to see all the options related to project metadata.
  4. Change Package Name to “com.example.jpa”
  5. Select WebJPA and Mysql dependencies.
  6. Click Generate to generate and download the project.

Configuring MySQL database and Hibernate Log levels

Let’s first configure the database URL, username, password, hibernate log levels and other properties.

Open src/main/resources/application.properties and add the following properties to it –

# DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url=jdbc:mysql://localhost:3306/jpa_element_collection_demo?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false
spring.datasource.username=root
spring.datasource.password=root

# Hibernate

# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect

# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update

logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type=TRACE

Please change spring.datasource.username and spring.datasource.password as per your MySQL installation. Also, create a database named jpa_element_collection_demo before proceeding to the next section.

Defining the Entity classes

Next, We’ll define the Entity classes that will be mapped to the database tables we saw earlier.

Before defining the User entity, let’s first define the Address type which will be embedded inside the User entity.

All the domain models will go inside the package com.example.jpa.model.

1. Address – Embeddable Type

package com.example.jpa.model;

import javax.persistence.Embeddable;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@Embeddable
public class Address {
    @NotNull
    @Size(max = 100)
    private String addressLine1;

    @NotNull
    @Size(max = 100)
    private String addressLine2;

    @NotNull
    @Size(max = 100)
    private String city;

    @NotNull
    @Size(max = 100)
    private String state;

    @NotNull
    @Size(max = 100)
    private String country;

    @NotNull
    @Size(max = 100)
    private String zipCode;

    public Address() {

    }

    public Address(String addressLine1, String addressLine2, String city, 
                   String state, String country, String zipCode) {
        this.addressLine1 = addressLine1;
        this.addressLine2 = addressLine2;
        this.city = city;
        this.state = state;
        this.country = country;
        this.zipCode = zipCode;
    }

    // Getters and Setters (Omitted for brevity)
}

2. User Entity

Let’s now see how we can map a collection of basic types (phone numbers) and embeddable types (addresses) using hibernate –

package com.example.jpa.model;

import javax.persistence.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.HashSet;
import java.util.Set;

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotNull
    @Size(max = 100)
    private String name;

    @NotNull
    @Email
    @Size(max = 100)
    @Column(unique = true)
    private String email;

    @ElementCollection
    @CollectionTable(name = "user_phone_numbers", joinColumns = @JoinColumn(name = "user_id"))
    @Column(name = "phone_number")
    private Set<String> phoneNumbers = new HashSet<>();

    @ElementCollection(fetch = FetchType.LAZY)
    @CollectionTable(name = "user_addresses", joinColumns = @JoinColumn(name = "user_id"))
    @AttributeOverrides({
            @AttributeOverride(name = "addressLine1", column = @Column(name = "house_number")),
            @AttributeOverride(name = "addressLine2", column = @Column(name = "street"))
    })
    private Set<Address> addresses = new HashSet<>();


    public User() {

    }

    public User(String name, String email, Set<String> phoneNumbers, Set<Address> addresses) {
        this.name = name;
        this.email = email;
        this.phoneNumbers = phoneNumbers;
        this.addresses = addresses;
    }

    // Getters and Setters (Omitted for brevity)
}

We use @ElementCollection annotation to declare an element-collection mapping. All the records of the collection are stored in a separate table. The configuration for this table is specified using the @CollectionTable annotation.

The @CollectionTable annotation is used to specify the name of the table that stores all the records of the collection, and the JoinColumn that refers to the primary table.

Moreover, When you’re using an Embeddable type with Element Collection, you can use the @AttributeOverrides and @AttributeOverride annotations to override/customize the fields of the embeddable type.

Defining the Repository

Next, Let’s create the repository for accessing the user’s data from the database. You need to create a new package called repository inside com.example.jpa package and add the following interface inside the repository package –

package com.example.jpa.repository;

import com.example.jpa.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {

}

Testing the ElementCollection Setup

Finally, Let’s write the code to test our setup in the main class JpaElementCollectionDemoApplication.java –

package com.example.jpa;

import com.example.jpa.model.Address;
import com.example.jpa.model.User;
import com.example.jpa.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.util.HashSet;
import java.util.Set;

@SpringBootApplication
public class JpaElementCollectionDemoApplication implements CommandLineRunner {

    @Autowired
    private UserRepository userRepository;

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

    @Override
    public void run(String... args) throws Exception {
        // Cleanup database tables.
        userRepository.deleteAll();

        // Insert a user with multiple phone numbers and addresses.
        Set<String> phoneNumbers = new HashSet<>();
        phoneNumbers.add("+91-9999999999");
        phoneNumbers.add("+91-9898989898");

        Set<Address> addresses = new HashSet<>();
        addresses.add(new Address("747", "Golf View Road", "Bangalore",
                "Karnataka", "India", "560008"));
        addresses.add(new Address("Plot No 44", "Electronic City", "Bangalore",
                "Karnataka", "India", "560001"));

        User user = new User("Yaniv Levy", "yaniv@fusebes.com",
                phoneNumbers, addresses);

        userRepository.save(user);
    }
}

The main class implements the CommandLineRunner interface and provides the implementation of its run() method.

The run() method is executed post application startup. In the run() method, we first cleanup all the tables and then insert a new user with multiple phone numbers and addresses.

You can run the application by typing mvn spring-boot:run from the root directory of the project.

After running the application, Go ahead and check all the tables in MySQL. The users table will have a new entry, the user_phone_numbers and user_addresses table will have two new entries –

mysql> select * from users;
+----+-----------------------+--------------------+
| id | email                 | name               |
+----+-----------------------+--------------------+
|  3 | yaniv@fusebes.com | Yaniv Levy |
+----+-----------------------+--------------------+
1 row in set (0.01 sec)
mysql> select * from user_phone_numbers;
+---------+----------------+
| user_id | phone_number   |
+---------+----------------+
|       3 | +91-9898989898 |
|       3 | +91-9999999999 |
+---------+----------------+
2 rows in set (0.00 sec)
mysql> select * from user_addresses;
+---------+--------------+-----------------+-----------+---------+-----------+----------+
| user_id | house_number | street          | city      | country | state     | zip_code |
+---------+--------------+-----------------+-----------+---------+-----------+----------+
|       3 | 747          | Golf View Road  | Bangalore | India   | Karnataka | 560008   |
|       3 | Plot No 44   | Electronic City | Bangalore | India   | Karnataka | 560001   |
+---------+--------------+-----------------+-----------+---------+-----------+----------+
2 rows in set (0.00 sec)

Conclusion

That’s all in this article Folks. I hope you learned how to use hibernate’s element-collection with Spring Boot.

Thanks for reading guys. Happy Coding! 🙂

Server Side Templating in Spring Boot using Thymeleaf
03
Mar
2021

Server Side Templating in Spring Boot using Thymeleaf

Thymeleaf is a serve-side template engine for Java. It has built-in support for Spring framework and is widely used in Spring based Projects.

In fact, Spring Boot itself has been promoting thymeleaf via several thymeleaf based projects and examples in its blog.

The purpose of this blog post is to build a Simple application with thymeleaf and Spring Boot, and learn all the details along the way.

Creating the Project

We’ll use Spring Initializr web tool to create our project. It is by far the simplest tool to generate a Spring Boot application.

Head over to http://start.spring.io and generate a project with the following details –

  • Group : com.example
  • Artifact : thymeleaf-tour
  • Dependencies : Web, Thymeleaf, DevTools
Spring Boot Thymeleaf Template Engine Example Tutorial

After generating the project, you must have got your project’s zip file. Unzip the file and import it in your favorite IDE.

The project’s directory structure looks like this –

Spring Boot Thymeleaf Template Engine Sample Directory Structure

Running the Application

You can run the application using the following command –

$ mvn spring-boot:run

The application will start on spring boot’s default tomcat port 8080. If you browse http://localhost:8080 on your web browser, the app will respond with a 404 error page because we haven’t created any server endpoint yet.

Let’s do that now.

Defining a Controller

First, Create a new package controller inside com.example.thymeleaftour package, and then create a new file HomeController with the following code –

package com.example.thymeleaftour.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class HomeController {

    private static final String appName = "ThymeleafTour";

    @GetMapping("/")
    public String home(Model model,
                       @RequestParam(value = "name", required = false,
                               defaultValue = "Guest") String name) {

        model.addAttribute("name", name);
        model.addAttribute("title", appName);
        return "home";

    }
}

In the above controller, We have defined a Request Parameter called name. This is an optional parameter with a default value of Guest.

Whenever a user requests the home page, we’ll display the application name and user’s name if it is supplied in the request parameter, or we’ll just show Hello Guest!

Next, We’re adding the name and title attributes to the Model so that they can be accessed from the template.

Finally, we’re returning the template name which will be used to render the response to the browser.

Creating a Thymeleaf Template

All Server side templates go into src/main/resources/templates directory. Create a new file called home.html inside the templates directory with the following contents –

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title th:text="${title}"></title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
    <div class="page-content">
        <h1 th:text="|Hello ${name}!|"></h1>
        <h2 th:text="|Welcome to ${title} application|"></h2>
    </div>
</body>
</html>

Notice the use of th:text attributes in the template above. It is a thymeleaf attribute, which evaluates the expression present in the value and sets the result as the body of the host tag.

The value "|Hello ${name}!|" in the template, is same as "'Hello' + ${name}". It’s just a syntactic sugar provided by thymeleaf for writing mixed expressions.

Adding static resources

Let’s add some css to our template. All static files in Spring Boot go to src/main/resources/static folder. Create a new folder css inside the static folder and then create a file main.css inside static/css.

Add the following styles to your css file –

body {
    background: #43cea2;
    background: -webkit-linear-gradient(to right, #185a9d, #43cea2); 
    background: linear-gradient(to right, #185a9d, #43cea2);
    color: #fff;
    text-align: center;
}

.page-content {
    position: absolute;
    text-align: center;
    left: 0;
    right: 0;
    top: 35%;
    bottom: 0;
}

h1 {
    font-size: 46px;
    margin-top: 10px;
    margin-bottom: 10px;
}

h2 {
    font-size: 34px;
    margin-top: 10px;
    margin-bottom: 10px;
}

Finally, We need to reference the css file inside home.html. Just add the following link tag in the head section of home.html file –

<link rel="stylesheet" href="/css/main.css" />

Running the application

You can run the application by going to the app’s root directory and typing the following command –

$ mvn spring-boot:run

You can browse the application at localhost:8080. Following is a screenshot of the app we just built –

Spring Boot Thymeleaf Example

Also, If you pass your name in the request parameter – http://localhost:8080?name=yaniv, then the app will greet you with your name instead of displaying Hello Guest.

Conclusion

In this tutorial, we learned how to use thymeleaf with Spring Boot. You can learn more about thymeleaf’s syntax and features from thymeleaf’s documentation.

Thank you for reading. Please ask any questions in the comment section below.

How to create a new file in Java
03
Mar
2021

How to create a new file in Java

There are various ways in which you can create a new file in Java. In this article, I’ve outlined the two most recommended way of creating new files.

You can use Files.createFile(path) method to create a new File in Java:

import java.io.IOException;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class CreateNewFile {

    public static void main(String[] args)  {
        // New file path
        Path filePath = Paths.get("./bar.txt");

        try {
            // Create a file at the specified file path
            Files.createFile(filePath);
            System.out.println("File created successfully!");

        } catch (FileAlreadyExistsException e) {
            System.out.println("File already exists");
        } catch (IOException e) {
            System.out.println("An I/O error occurred: " + e.getMessage());
        } catch (SecurityException e) {
            System.out.println("No permission to create file: " + e.getMessage());
        }
    }
}

Create New File with missing parent directories using Java NIO

There are scenarios in which you may want to create any missing parent directories while creating a File. You can use Files.createDirectories(path) function to create missing parent directories before creating the file.

import java.io.IOException;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class CreateNewFile {

    public static void main(String[] args)  {
        // New file path
        Path filePath = Paths.get("java/io/bar.txt");

        try {
            // Create missing parent directories
            if(filePath.getParent() != null) {
                Files.createDirectories(filePath.getParent());
            }

            // Create a file at the specified file path
            Files.createFile(filePath);
            System.out.println("File created successfully!");

        } catch (FileAlreadyExistsException e) {
            System.out.println("File already exists");
        } catch (IOException e) {
            System.out.println("An I/O error occurred: " + e.getMessage());
        } catch (SecurityException e) {
            System.out.println("No permission to create file: " + e.getMessage());
        }
    }
}

Create New File in Java using java.io.File class – JDK 6+

You can also use the File.createNewFile() method to create a new File in Java. It returns a boolean value which is –

  • true, if the file does not exist and was created successfully
  • false, if the file already exists
import java.io.File;
import java.io.IOException;

public class CreateNewFile {

    public static void main(String[] args) {
        // Instantiate a File object with a file path
        File file = new File("./foo.txt");

        try {
            // Create the file in the filesystem
            boolean success = file.createNewFile();

            if (success) {
                System.out.println("File created successfully!");
            } else {
                System.out.println("File already exists!");
            }
        } catch (IOException e) {
            System.out.println("An I/O error occurred: " + e.getMessage());
        } catch (SecurityException e) {
            System.out.println("No sufficient permission to create file: " + e.getMessage());
        }
    }
}

Create New File along with missing parent directories with java.io.File class

If you want to create missing parent directories while creating a file, then you can explicitly creaate the directories by calling file.getParentFile().mkdirs() method:

import java.io.File;
import java.io.IOException;

public class CreateNewFile {

    public static void main(String[] args) {
        // Instantiate a File object with a file path
        File file = new File("java/io/foo.txt");

        try {
            // Create missing parent directories
            if(file.getParentFile() != null) {
                file.getParentFile().mkdirs();
            }

            // Create the file
            boolean success = file.createNewFile();

            if (success) {
                System.out.println("File created successfully!");
            } else {
                System.out.println("File already exists!");
            }
        } catch (IOException e) {
            System.out.println("An I/O error occurred: " + e.getMessage());
        } catch (SecurityException e) {
            System.out.println("No sufficient permission to create file: " + e.getMessage());
        }
    }
}
Convert a String to Date (LocalDate, LocalDateTime, ZonedDateTime, LocalTime) in Java
03
Mar
2021

Convert a String to Date (LocalDate, LocalDateTime, ZonedDateTime, LocalTime) in Java

In this article, you’ll find several examples demonstrating how to convert a date represented as a String to a Date, LocalDate, LocalDateTime, ZonedDateTime, or LocalTime instance in Java.

How to convert a String to Date in Java using SimpleDateFormat

Dates are represented as Strings by using some patterns and symbols. Java’s SimpleDateFormat class uses the following patterns and symbols for parsing a String to Date.

SimpleDateFormat Date and Time Patterns

Let’s see an example:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class SimpleDateFormatExample {
    public static void main(String[] args) {
        SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd");
        String dateStr = "2020-01-31";

        try {
            // Parsing a String to Date
            Date date = dateFormatter.parse(dateStr);
            System.out.println(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

Here is another example in which we parse a more complex date time representation:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class SimpleDateFormatExample {
    public static void main(String[] args) {
        SimpleDateFormat dateTimeFormatter = new SimpleDateFormat("E, MMM dd yyyy, hh:mm:ss a");
        String dateTimeStr = "Fri, Jan 31 2020, 10:30:45 PM";

        try {
            // Parse the String representation of date and time to Date
            Date date = dateTimeFormatter.parse(dateTimeStr);
            System.out.println(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

Convert/Parse a String to LocalDate

We can also use the DateTime API introduced in Java 8 to convert a String to an instance of various DateTime classes like LocalDate, LocalTime, LocalDateTime, ZonedDateTime etc.

The DateTime API has a DateTimeFormatter class that can be used to define the date time format and parse the String according to the specified date time format. The DateTimeFormatter class uses the following patterns and symbols:

DateTimeFormatter Patterns and Symbols

Let’s see an example of parsing a String to LocalDate:

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class LocalDateParseExample {
    public static void main(String[] args) {
        // Parse a String in ISO Date format (yyyy-MM-dd) to LocalDate
        LocalDate date1 = LocalDate.parse("2020-02-28");
        System.out.println(date1);

        // Parse a String in a custom date format to LocalDate using DateTimeFormatter
        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
        LocalDate date2 = LocalDate.parse("28/02/2020", dateFormatter);
        System.out.println(date2);

        // Parse a String in a custom date-time format to LocalDate using DateTimeFormatter
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("E, MMM dd yyyy, hh:mm:ss a");
        LocalDate date3 = LocalDate.parse("Fri, Feb 14 2020, 10:20:50 PM", dateTimeFormatter);
        System.out.println(date3);

    }
}

Convert/Parse a String to LocalDateTime

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

public class LocalDateTimeParseExample {
    public static void main(String[] args) {
        // Parse a String in ISO DateTime format (yyyy-MM-ddTHH:mm:ss) to LocalDateTime
        LocalDateTime dateTime1 = LocalDateTime.parse("2020-01-31T10:15:30");
        System.out.println(dateTime1);

        // Parse a String in a custom date format to LocalDate using DateTimeFormatter
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("MMM dd yyyy, HH:mm");
        LocalDateTime dateTime2 = LocalDateTime.parse("Jan 11 2020, 10:30", dateTimeFormatter);
        System.out.println(dateTime2);

        // Parse a String in a custom DateTime format to LocalDateTime using DateTimeFormatter
        DateTimeFormatter descriptiveDateTimeFormatter = DateTimeFormatter.ofPattern("E, MMM dd yyyy, hh:mm:ss a");
        LocalDateTime dateTime3 = LocalDateTime.parse("Fri, Feb 14 2020, 10:20:50 PM", descriptiveDateTimeFormatter);
        System.out.println(dateTime3);

    }
}

Convert/Parse a String to LocalTime

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public class LocalTimeParseExample {
    public static void main(String[] args) {
        // Parse a String in ISO Time format (HH:mm:ss) to LocalDate
        LocalTime time1 = LocalTime.parse("12:30:50");
        System.out.println(time1);

        // Parse a String in a custom date format to LocalTime using DateTimeFormatter
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");
        LocalTime time2 = LocalTime.parse("28/02/2020 16:45:30", dateTimeFormatter);
        System.out.println(time2);

    }
}

Convert/Parse a String to ZonedDateTime

import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

public class ZonedDateTimeParseExample {
    public static void main(String[] args) {
        // Parse a String in ISO DateTime format to ZonedDateTime
        ZonedDateTime dateTime1 = ZonedDateTime.parse("2020-01-31T10:15:30+01:00[Europe/Paris]");
        System.out.println(dateTime1);

        // Parse a String in a custom date time format to ZonedDateTime using DateTimeFormatter
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("MMM dd yyyy, HH:mm (VV)");
        ZonedDateTime dateTime2 = ZonedDateTime.parse("Jan 11 2020, 10:30 (America/Los_Angeles)", dateTimeFormatter);
        System.out.println(dateTime2);
    }
}