Enterprise Java

Image Display and Upload with Thymeleaf, Spring MVC, and MySQL

Photo of Omozegie AziegbeOmozegie AziegbeJanuary 19th, 2024Last Updated: January 19th, 2024
0 2,271 7 minutes read

In modern web development, the ability to seamlessly display images from various sources and allow users to upload images are common requirements. This article explores the dynamic display of images through Spring Boot and Thymeleaf.Thymeleaf is a server-side Java template engine that integrates seamlessly with Spring MVC to provide an efficient way to handle dynamic content rendering.

1. Setting Up the Spring Boot Project

Thymeleaf simplifies the process of rendering dynamic content, including images, within Spring MVC applications. Here’s a guide on how to display images from different sources using Thymeleaf.

1.1 Maven Dependencies

Let us begin by creating a new Spring Boot project in our preferred IDE or by using Spring Initializer to set up the project with the necessary dependencies, including Spring Boot starters for web development, Thymeleaf for template rendering, Spring Data JPA for database access, MySQL Connector for connecting to a MySQL database, Spring Boot Starter Test for testing, and additional Thymeleaf extras.

         <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-springsecurity6</artifactId></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><scope>provided</scope></dependency></dependencies>

Once our project is ready, we can proceed to configure the application properties (src/main/resources/application.properties) like this:

1.2 Application Properties

# Set Thymeleaf template prefix and suffixspring.thymeleaf.prefix=classpath:/templates/spring.thymeleaf.suffix=.htmlspring.thymeleaf.cache=false# DataSource Configurationspring.datasource.url=jdbc:mysql://localhost:3306/displayimagesthymeleaf?useSSL=falsespring.datasource.username=your_usernamespring.datasource.password=your_passwordspring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver# JPA (Java Persistence API) Configurationspring.jpa.hibernate.ddl-auto=updatespring.jpa.show-sql=true# Server Portserver.port=8080

2. Fetching Images from the File System

To demonstrate image display from the local file system, let’s start by organizing the static resources.

2.1 Organizing Static Resources

Create astatic directory within thesrc/main/resources directory. This is where static resources, including images, will be stored. For example, if we have an image namedexample.jpg, place it in thesrc/main/resources/static/images directory. The project structure should look like this:

Fig 1: Project structure for thymeleaf to display static images
Fig 1: Project structure for thymeleaf to display static images

2.2 Thymeleaf Template for Static Image Display

Next, create a Thymeleaf template that references the static image. Thymeleaf simplifies the integration of dynamic content, including static resources, into HTML templates. We have created an HTML page namedimagedisplay.html inside thesrc/main/resources/templates/ directory.

<!DOCTYPE html><html lang="en" xmlns:th="http://www.thymeleaf.org"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>Static Image Display</title></head><body>    <h1>Displaying Static Images in Spring Boot</h1>    <!-- Display static image -->    <img th:src="@{/images/example.jpg}" alt="Example Image"></body></html>

In the above example,@{/images/example.jpg} references the static image in theimages directory. The@{/} syntax is used to specify the root context path.

2.3 Controller for Thymeleaf Display

Next, create a controller class to handle requests and direct them to the Thymeleaf template.

@Controllerpublic class ImageController {         @GetMapping("/display")    public String displayImage() {        return "imagedisplay";    }}

This controller maps the/display URL to the Thymeleaf template, allowing users to view the static image.

Run the Spring Boot application and navigate tohttp://localhost:8080/display (assuming the application is running on port 8080). We should see the Thymeleaf template displaying the static image.

Fig 2: static image display in thymeleaf + spring boot
Fig 2: static image display in thymeleaf + spring boot

2.4 External URL

Fetching images from an external URL involves using the URL of the desired image like this:

    <!-- External URL -->    <img th:src="@{https://path/to/the/externalURL/image/logo.png}" alt="External Image">

3. Fetching Images from a Database using JPA

We can employ Java Persistence API (JPA) entities and repositories for database-backed image retrieval. Let’s create the SQL statements to generate the necessary tables in our MySQL database:

CREATE TABLE image_entity (    id BIGINT AUTO_INCREMENT PRIMARY KEY,    image_name VARCHAR(255),    image_data LONGBLOB);

This SQL statement defines a table namedimage_entity with columns forID,image_name, andimage_data stored as aLONGBLOB.

3.1 Database Entity and Repository

Create a JPA entity to represent the images and a repository interface for database interactions.

3.1.1 Define Entity Class

Create an entity class to represent the image data. This class should have a field of typebyte[] to store the image as a BLOB (Binary Large Object).

@Entitypublic class ImageEntity {    @Id    @GeneratedValue(strategy = GenerationType.IDENTITY)    private Long id;    @Column    private String imageName;    @Lob    @Column    private byte[] imageData;    public ImageEntity() {    }    public ImageEntity(Long id, String imageName, byte[] imageData) {        this.id = id;        this.imageName = imageName;        this.imageData = imageData;    }    public Long getId() {        return id;    }    public void setId(Long id) {        this.id = id;    }    public String getImageName() {        return imageName;    }    public void setImageName(String imageName) {        this.imageName = imageName;    }    public byte[] getImageData() {        return imageData;    }    public void setImageData(byte[] imageData) {        this.imageData = imageData;    }     public String getImageDataBase64() {        return Base64.encodeBase64String(this.imageData);    }    }

3.1.2 Create a Repository Interface

Next, create a repository interface that extendsJpaRepository to perform CRUD operations on theImageEntity.

public interface ImageRepository extends JpaRepository {}

3.2 Service Layer

Next, create a service class that handles business logic. In this example, it involves saving and retrieving images from the database.

ThisImageService class encapsulates the logic related to image manipulation and interaction with the database.

@Servicepublic class ImageService {    @Autowired    private ImageRepository imageRepository;    public List getAllImages() {        return imageRepository.findAll();    }    public Optional getImageById(Long id) {        return imageRepository.findById(id);    }    public void saveImage(ImageEntity imageEntity, MultipartFile file) {        try {            imageEntity.setImageData(file.getBytes());            imageRepository.save(imageEntity);        } catch (IOException ex) {            Logger.getLogger(ImageService.class.getName()).log(Level.SEVERE, null, ex);        }            }}

In the above code, thesaveImage(ImageEntity imageEntity, MultipartFile file)method saves an image to the database. It takes anImageEntity object and aMultipartFile representing the image file uploaded by a user through a form. It reads the content of the uploaded file as a byte array usingfile.getBytes() and sets it as theimageData property of theImageEntity. Then, it saves the modifiedImageEntity to the database using thesave() method provided by the injectedimageRepository.

3.3 Controller for Image Upload and Display

Next, we create a controller class to handle requests related to image operations. This controller is responsible for displaying a view that shows a list of images (/imagedisplay/view) and handling the addition of new images (/imagedisplay/add) as shown below:

@Controllerpublic class DatabaseImageController {    @Autowired    private ImageService imageService;        @GetMapping(value = "/imagedisplay/view", produces = {MediaType.IMAGE_JPEG_VALUE, MediaType.IMAGE_PNG_VALUE})    public String view(Model model) {        model.addAttribute("images", imageService.getAllImages());        return "view";    }    @GetMapping("/imagedisplay/add")    public ModelAndView addImage() {        return new ModelAndView("addImage", "image", new ImageEntity());    }    @PostMapping(value = "/imagedisplay/add", consumes = MULTIPART_FORM_DATA_VALUE)    public String addImageProfile(ImageEntity image, @RequestPart("file") MultipartFile file) {        imageService.saveImage(image, file);        return "redirect:/imagedisplay/view";    }    }

Here is an explanation of the main part of the code:

  • @GetMapping("/imagedisplay/view") Method:
    • This method handlesHTTP GET requests for the/imagedisplay/view endpoint. It produces images in JPEG or PNG format (as specified by theproduces attribute). It adds a list of images retrieved from the database usingimageService.getAllImages() to the model and returns the view nameview. This view is used to display the images.
  • @GetMapping("/imagedisplay/add") Method:
    • This method handlesHTTP GET requests for the/imagedisplay/add endpoint. It returns aModelAndView object with the view nameaddImage and an instance ofImageEntity bound to theimage model attribute. This is used for displaying a form for adding images.
  • @PostMapping("/imagedisplay/add") Method:
    • This method handlesHTTP POST requests for the/imagedisplay/add endpoint. It consumes multipart form data (consumes = MULTIPART_FORM_DATA_VALUE). It takes anImageEntity object and aMultipartFile as parameters, representing the image and the file being uploaded. It saves the image using theimageService.saveImage(image, file) method and then redirects the user to the/imagedisplay/view endpoint.

3.4 Displaying Images Fetched from Database using Thymeleaf Template

Next, create a Thymeleaf template to display images fetched from the database dynamically. Create a file namedaddImage.html to upload images to the database and a file namedview.html within thesrc/main/resources/templates/ directory.

<!-- addImage.html --><!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org">    <head>        <meta charset="UTF-8">        <meta name="viewport" content="width=device-width, initial-scale=1.0">        <title>Image Upload Form</title>        <style>                   </style>    </head>    <body>        <div>            <form th:action="@{/imagedisplay/add}" method="post" enctype="multipart/form-data">                <p>Image Upload Form</p>                <p><label for="file">Select image:</label>                    <input type="file" name="file" accept="image/png, image/jpeg" required/>                </p>                <p><label for="imageName">Image Name:</label>                    <input type="text" name="imageName" required><br>                </p>                <p>                    <input type="submit" value="Upload">                </p>            </form>        </div>    </body></html>
Fig 2: Image Upload form
Fig 2: Image Upload form
<!-- view.html --><!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org">    <head>        <meta charset="UTF-8">        <meta name="viewport" content="width=device-width, initial-scale=1.0"/>        <title>Image List</title>              </head>    <body>        <div th:each="image : ${images}">               <img  th:src="@{'data:image/jpeg;base64,'+${image.getImageDataBase64()}}" alt="images from database" width="50%" height="50%"/>            <p th:text="Figure + ' '+ ${image.id} + ':' + ${image.imageName}"></p>         </div>    </body></html>

In the above Thymeleaf template, theth:src attribute now uses the Base64-encoded string returned bygetImageDataBase64 to display the image.

Fig 3: View page showing all the Images fetched from the database
Fig 3: View page showing all the Images fetched from the database

4. Securing Access to Images to Ensure Unauthorized Entry

To prevent unauthorized access to images using Spring Security, we can enhance our Spring Boot application by securing the endpoints that serve the images. Below are the modifications and additions to our existing code.

4.1 Add Spring Security Dependency

Ensure that you have the Spring Security dependency in yourpom.xml:

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

4.2 Create or Update SecurityConfig Class

Create aSecurityConfig class to configure Spring Security in the application:

@Configuration@EnableWebSecuritypublic class SecurityConfig {    @Bean    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {            http.authorizeRequests()                .requestMatchers("/").permitAll()                .requestMatchers("/display/**").permitAll()                .requestMatchers("/images/**").permitAll() // Permit access to static images                .requestMatchers("/imagedisplay/view").authenticated() // Require authentication for image view                .anyRequest().authenticated();                        return http.build();    }}

In this example, the pattern/images/** is used to permit access to static images, assuming our static images are served from a directory namedimages under thestatic folder.

The.requestMatchers("/images/**").permitAll() method allows access to all URLs starting with/images/ without authentication. This is used for serving the static images.

We secured the/imagedisplay/view endpoint to require authentication.

The.requestMatchers("/imagedisplay/view").authenticated() requires authentication for the/imagedisplay/view URL, therefore users must be authenticated to access this endpoint.

5. Conclusion

This article has provided us with the full source code examples to implement static image display and dynamic image display from a MySQL database using Thymeleaf, Spring Boot, and JPA.

Displaying static images from the resources directory in a Spring Boot project is a straightforward process. By organizing static resources in thestatic directory and leveraging Thymeleaf for template rendering, we can easily integrate static images into our web applications.

Furthermore, the combination of Thymeleaf templates and Spring Boot’s backend framework has allowed us to effortlessly render dynamic images retrieved from the MySQL database, utilizing JPA for efficient data access and management.

6. Download the Source Code

This was an example of using thymeleaf to display images.

Download
You can download the full source code of this example here:Image Display and Upload with Thymeleaf, Spring MVC, and MySQL
Do you want to know how to develop your skillset to become aJava Rockstar?
Subscribe to our newsletter to start Rockingright now!
To get you started we give you our best selling eBooks forFREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to theTerms andPrivacy Policy

Thank you!

We will contact you soon.

Photo of Omozegie AziegbeOmozegie AziegbeJanuary 19th, 2024Last Updated: January 19th, 2024
0 2,271 7 minutes read
Photo of Omozegie Aziegbe

Omozegie Aziegbe

Omos holds a Master degree in Information Engineering with Network Management from the Robert Gordon University, Aberdeen. Omos is currently a freelance web/application developer who is currently focused on developing Java enterprise applications with the Jakarta EE framework.
Subscribe
Notify of
guest
I agree to theTerms andPrivacy Policy
The comment form collects your name, email and content to allow us keep track of the comments placed on the website. Please read and accept our website Terms and Privacy Policy to post a comment.

I agree to theTerms andPrivacy Policy
The comment form collects your name, email and content to allow us keep track of the comments placed on the website. Please read and accept our website Terms and Privacy Policy to post a comment.