Monthly Archives: June 2019

How to file upload using Spring Boot

In this post, I will show how I added file upload functionality in my Spring Boot application, social KPI.

On the outskirts, it looks very simple functionality and it is indeed simple with Spring Boot. As part of this post, we will build a web form where an administrator will add additional users for his/her company by importing a CSV file in a particular format.

Basic functionality is to provide a way for an administrator to import a CSV file, read and validate the data, and save it in the database if proper data.

Now once we have defined our user story, let’s get started with the post.

Form For File Upload In a Spring Boot Application

We are using thymeleaf templates for our spring boot based application. So writing a simple html page with a form to upload a file is very straight forward as below:

<div class="container importuser">
    <div class="form-group">
    <form method="POST" th:action="@{/uploadUsers}" enctype="multipart/form-data">
        <input type="hidden" name="companyGuid" th:value="${companyGuid}"/>
        <input type="file" name="file"/></br></br>
        <button type="submit" class="btn btn-primary btn-lg" value="Import">Import
        </button>
    </form>
    </div>
</div>

As you see in this form, clicking on Import button will kick the action to upload users.

Controller to handle file upload on backend side

A controller to handle upload users functionality will look like below:

    @RequestMapping(value = "/uploadUsers",method= RequestMethod.POST)
    public String fileUpload (@RequestParam("file") MultipartFile file, @RequestParam(
            "companyGuid") String companyGuid,
                              RedirectAttributes redirectAttributes)
    {
        LOGGER.info("File is {}", file.getName());
        LOGGER.info("Company Guid is {}", companyGuid);

        if (file.isEmpty())
        {
            redirectAttributes.addFlashAttribute("message", "Please select a file to upload");
            return "redirect:/uploadStatus";
        }

        List userList = FileUtil.readAndValidateFile(file, roleRepository);
        for(User user: userList)
        {
            User createdUser = userManager.createUser(companyGuid, user);
        }

        redirectAttributes.addFlashAttribute("message",
                "You successfully uploaded " + file.getOriginalFilename() + " and added " + userList.size() + " users");


        return "redirect:/uploadStatus";
    }

The method to readAndValidateFile is simply reading the data from file, validating to make sure all the fields in CSV file exists, if wrong format, it will throw an error. If a valid file, it will create a list of users. UserManager will create each user.

The class FileUtil is as below:

package com.betterjavacode.socialpie.utils;

import com.betterjavacode.socialpie.models.Role;
import com.betterjavacode.socialpie.models.User;

import com.betterjavacode.socialpie.repositories.RoleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class FileUtil
{
    private static final String FIRST_NAME = "firstname";
    private static final String LAST_NAME = "lastname";


    public static List readAndValidateFile (MultipartFile file, RoleRepository roleRepository)
    {
        BufferedReader bufferedReader;
        List result = new ArrayList<>();
        try
        {
            String line;
            InputStream inputStream = file.getInputStream();
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            while((line = bufferedReader.readLine()) != null)
            {
                String[] userData = line.split(",");
                if(userData == null || userData.length != 5)
                {
                    throw new RuntimeException("File data not in correct format");
                }
                if(FIRST_NAME.equalsIgnoreCase(userData[0]) && LAST_NAME.equalsIgnoreCase(userData[2]))
                {
                    continue; // first line is header
                }
                User user = new User();
                user.setFirstName(userData[0]);
                user.setMiddleName(userData[1]);
                user.setLastName(userData[2]);
                user.setEmail(userData[3]);
                Role role = roleRepository.findByRoleName(userData[4]);
                user.setRole(role);
                result.add(user);
            }
        }
        catch(IOException e)
        {
            throw new RuntimeException("Unable to open the file " + e.getMessage());
        }
        return result;
    }
}

A working demo

Once I log into the application Social KPI, I click on Add Users and it will take me to upload the users screen which will look below:

Spring Boot File Upload

Import Users

Once you choose a file in CSV format to upload and click on Import, it will show the screen as below:

Spring Boot File Upload - Upload Status

File Upload Status

Conclusion

So in this post, we showed how to import a file while using Spring Boot multipart form.

References

  1. Uploading files – uploading files

Metrics collection with Micrometer and Prometheus

In my previous post here, I showed how to configure Micrometer and Prometheus to collect microservice performance metrics data. In this post, I will show how we can collect Spring Boot Actuator metrics data and transfer to Prometheus UI, and view it using dashboards.

Spring Boot offers a lot of great features with Actuator. With enterprise applications constantly looking for ways to monitor the application, these metrics become even more important.

Configure Prometheus using the docker

Firstly, we will configure the Prometheus. Depending on the environment you are using, start the docker terminal. Use the following command to download Prometheus

docker pull prom/prometheus

We will configure Prometheus to scrape metrics from our application’s actuator endpoint. As shown in the previous post here, spring boot actuator endpoint is running on http://localhost:8080/actuator/prometheus

We will add Prometheus configuration in prometheus.yml file as below:

# my global config
global:
  scrape_interval:     5s # Set the scrape interval to every 5 seconds. Default is every 1 minute.
  evaluation_interval: 5s # Evaluate rules every 5 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).
 
# Alertmanager configuration
alerting:
  alertmanagers:
  - static_configs:
    - targets:
      # - alertmanager:9093
 
# 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: ['localhost:9090']
 
  - job_name: 'spring-actuator'
    metrics_path: '/actuator/prometheus'
    scrape_interval: 5s
    static_configs:
    - targets: ['IPADDRESS_OF_HOST:8080']

Few things to notice from this configuration file. scrape_interval is 5s. In scrape_configs , job name for our Spring Actuator endpoint is spring-actuator and the endpoint is running at /actuator/prometheus. The targets section shows where our application is running.  Save this file at a location that we can use to mount while running the docker container.

To Run the Prometheus using docker, use the following command:

docker run --name prometheus -d --mount type=bind,source=//c/Users/sandbox/prometheus.yml,destination=/etc/prometheus/prometheus.yml -p 9090:9090 prom/prometheus

This will start the Prometheus server at 9090 and it can be accessed at 9090.  Meanwhile, we can check the Prometheus dashboard. Let’s get the docker IP first by using the following command

docker-machine ip

Now check the Prometheus dashboard at http://docker-ip:9090 , it will look like below:

Spring Boot Actuator Metrics in Prometheus Dashboard

Conclusion

In this post, we showed how to run a Prometheus out of docker container and scrape metrics from Spring boot application.

References

  1. Spring Boot and Prometheus – Spring boot actuator and Prometheus
  2. Monitoring your microservices – Monitoring your microservices