Store Image As Blob And Retrieve Blob As Image Using Spring

Image As Blob And Blob As Image

Here in this example I am going to show you how to store image as blob into database. While retrieving blob from database I am going to display blob as image. While storing image as blob into database I am going to display a page which will be used for uploading the image. I am also going to show you how to download blob as an image from database. You can also delete the image you don’t want to keep.

In this example I am going to use spring data jpa to save image as blob into database or retrieve blob as image. I am using Thymeleaf framework for front-end or user interface (ui) pages.

Prerequisites

Java 19, Maven 3.8.5, Spring Boot 3.2.0, MySQL 8.1.0

Project Setup

You can use the following pom.xml file for your project reference:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.roytuts</groupId>
	<artifactId>spring-image-blob-image</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>19</maven.compiler.source>
		<maven.compiler.target>19</maven.compiler.target>
	</properties>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.2.0</version>
	</parent>

	<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>com.mysql</groupId>
			<artifactId>mysql-connector-j</artifactId>
		</dependency>

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

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

Data Source

The following content is written into src/main/resources/application.properties file for data source configuration purpose.

As I have configured the data source details with standard naming convention so I don’t need to create a bean for data source. An instance of the data source will be created by spring container automatically.

#datasource
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/roytuts
spring.datasource.username=root
spring.datasource.password=root

Entity Class

The entity class is mapped with the corresponding database table.

I have the same Java attribute names and column names except the one date. So I don’t need to specify the class attributes with @Column annotations.

Notice in the following class the blob type of column in database table has been annotated with @Lob annotation and the data type has been specified as array of byte.

package com.roytuts.spring.image.blob.entity;


@Entity
@Table(name = "images")
public class Image implements Serializable {

	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer id;

	private String name;

	@Lob
	private byte[] content;

	@Column(name = "save_date")
	private String date;

        ...
}

Repository

I am here using spring data jpa repository so I won’t write any query and I will use the built-in methods to query the database table.

package com.roytuts.spring.image.blob.repository;

public interface ImageRepository extends JpaRepository<Image, Integer>{

}

Service Class

The service class is responsible for performing business logic.

package com.roytuts.spring.image.blob.service;


@Service
public class ImageService {

	@Autowired
	private ImageRepository imageRepository;

	public void saveImage(Image image) {
		imageRepository.save(image);
	}

	public void deleteImage(Integer id) {
		imageRepository.deleteById(id);
	}

	public Image getImage(Integer id) {
		return imageRepository.findById(id).get();
	}

	public List<Image> imageList() {
		return imageRepository.findAll();
	}

}

Controller Class

The controller class is responsible for handling requests/responses for clients or end users. This controller class also validates input fields. The controller class defines methods for uploading, displaying and downloading images.

In the following controller class I have validated the input file whether it is an image or not.

The downloaded image is saved into the default location or it will ask where to save the image.

package com.roytuts.spring.image.blob.controller;

@Controller
public class ImageController {

	@Autowired
	private ImageService imageService;

	@GetMapping("/")
	public String imageList(ModelMap modelMap) {
		List<Image> images = imageService.imageList();

		modelMap.addAttribute("imageList", images);

		return "images";
	}

	@GetMapping("/uploadImage")
	public String uploadImage() {
		return "upload";
	}

	@PostMapping("/upload/image")
	public String uploadImage(@RequestParam("image") MultipartFile image, ModelMap modelMap) throws IOException {
		String imageName = image.getOriginalFilename();

		String ext = Objects.requireNonNull(imageName).substring(imageName.lastIndexOf('.') + 1).toLowerCase();

		if (ext.equals("jpeg") || ext.equals("jpe") || ext.equals("jpg") || ext.equals("png") || ext.equals("gif")) {
			byte[] content = image.getBytes();

			DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd-MM-yyyy hh:mm:ss");

			Image img = new Image();
			img.setName(imageName);
			img.setContent(content);
			img.setDate(dtf.format(LocalDateTime.now()));

			imageService.saveImage(img);

			modelMap.addAttribute("msg", "Image '" + imageName + "' Successfully Uploaded");
		} else {
			modelMap.addAttribute("msg", "Image '" + imageName + "' must be an image file (jpeg/png/gif)");
		}

		return "upload";
	}

	@ResponseBody
	@GetMapping("/download/image/{id}")
	public ResponseEntity<Resource> downloadImages(@PathVariable int id) {
		Image img = imageService.getImage(id);

		ByteArrayResource resource = new ByteArrayResource(img.getContent());

		return ResponseEntity.ok().contentType(MediaType.valueOf(img.getMimeType()))
				.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + img.getName() + "\"")
				.body(resource);
	}

	@GetMapping("/delete/image/{id}")
	public String deleteImage(@PathVariable int id, ModelMap modelMap) {
		imageService.deleteImage(id);

		List<Image> images = imageService.imageList();

		modelMap.addAttribute("imageList", images);
		modelMap.addAttribute("msg", "Image deleted successfully");

		return "redirect:/";
	}

}

Spring Boot Main Class

A class with main method and @SpringBootApplication annotation is required to deploy the application into the embedded Tomcat server.

package com.roytuts.spring.image.blob;


@SpringBootApplication
public class App {

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

}

User Interface Pages

There are mainly two pages – one for uploading image and another for displaying, downloading and deleting images.

The content of the pages is written using Thymeleaf framework, so I am using HTML pages for building UI pages.

images.html

The following page images.html will provide links for downloading and deleting image(s).

<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Display Image Files</title>
</head>
<body>
	<p><a th:href="@{'/uploadImage'}" title="Upload A New Image">Upload An Image</a></p>

	<div th:if="${msg != null}" th:text="${msg}"></div>
	
	<div th:if="${imageList.size() > 0}">
		<h2>List of Images</h2>
		
		<table cellpadding="5" cellspacing="5" border="1">
			<thead>
				<tr>
					<th>ID</th>
					<th>Name</th>
					<th>Image</th>
					<th>Actions</th>
				</tr>
			</thead>
			<tbody>
				<tr th:each="img : ${imageList}">
					<td>[[${img.id}]]</td>
					<td>[[${img.name}]]</td>
					<td><img th:src="@{'data:${img.getMimeType()};base64,'+${img.generateBase64Image()}}" alt="picture" height="200" width="250"></td>
					<td>
						<a th:href="@{'/download/image/' + ${img.id}}" title="Download">Download</a>
						<a th:href="@{'/delete/image/' + ${img.id}}" onclick="return confirm('Do you really want to delete?')" title="Delete">Delete</a>
					</td>
				</tr>
			</tbody>
		</table>
	</div>
</body>
</html>

upload.html

The upload.html page is required to upload an image by selecting it using the browse button from any disk space or any other place.

<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Upload Image File</title>
</head>
<body>
	<p><a th:href="@{'/'}" title="Images">List Of Images</a></p>
	
    <h2>Upload An Image File</h2>

	<div th:if="${msg != null}" th:text="${msg}"></div>

	<form enctype="multipart/form-data"	th:action="@{/upload/image}" method='POST'>
		<p>Select Image: <input type="file" name="image"/></p>
		<p><input value="Upload" type="submit"/></p>
	</form>
</body>
</html>

That’s all about coding part. Now let’s test the application.

Testing Image Application

You can now run the main class and once the application deployed successfully in Tomcat server you can access the URL http://localhost:8080/ in the browser and you will find the following page for uploading an image.

spring image blob

Initially you won’t find any image displayed on the page as there is no uploaded image.

Now you can click on the Upload An Image link to upload an image using the following page:

spring blob image

You can upload as many images as you wish, here I have uploaded two images and those are displayed as follows:

image blob spring

You can either download or delete the image from the list of images. When you try to delete an image you will need to confirm before deletion to prevent the image from accidentally deleted:

image blob database

Hope you got an idea how to store an image into database as a blob type and how to retrieve blob type data as an image from database.

Source Code

Download

Leave a Reply

Your email address will not be published. Required fields are marked *