In previous post, we’ve known how to upload and download files with a Spring Boot and Thymeleaf. In this tutorial, I will continue to show you way to delete file (if it exists) in Spring Boot.
Related Posts:
– Spring Boot File upload REST API example
– Spring Boot Thymeleaf CRUD example
– Spring Boot Thymeleaf Pagination and Sorting example
– Spring Boot @ControllerAdvice & @ExceptionHandler example
– @RestControllerAdvice example in Spring Boot
– Spring Boot Unit Test for JPA Repository
– Spring Boot Unit Test for Rest Controller
– Deploy Spring Boot App on AWS – Elastic Beanstalk
Fullstack:
– Angular + Spring Boot: File upload example
– React + Spring Boot: File upload example
Associations:
– Spring Boot One To One example with JPA, Hibernate
– Spring Boot One To Many example with JPA, Hibernate
– Spring Boot Many to Many example with JPA, Hibernate
Contents
Spring Boot Delete File with Thymeleaf example
Our Spring Boot Application has already features for:
– uploading File to a static folder in the Server
– downloading File from server with the link
– getting list of Files’ information (file name & url)
Today we continue to implement Delete File feature:
1- User clicks on Trash icon.
2- A Confirmation dialog appears to ask user to approve DELETE operation.
3- User decides whether to delete the file or not.
Technology
- Java 8
- Spring Boot 2.7 (with Spring Web MVC, Thymeleaf)
- Maven 3.6.1
- Bootstrap 4
- jQuery 3.6.1
Project Structure
We will add some functions to existing Spring Boot project:
Thymeleaf File Upload with Spring Boot
Let me explain it briefly.
– FileInfo
contains information of the uploaded file.
– FilesStorageService
helps us to initialize storage, save new file, load file, get list of Files’ info, DELETE files.
– FileController
uses FilesStorageService
to handle file upload/download and template requests.
– FileUploadExceptionAdvice
handles exception when the controller processes file upload.
– template
stores HTML template files for the project.
– application.properties contains configuration for Servlet Multipart.
– uploads is the static folder for storing files.
– pom.xml for Spring Boot dependency.
Setup Spring Boot Delete File with Thymeleaf project
Use Spring web tool or your development tool (Spring Tool Suite, Eclipse, Intellij) to create a Spring Boot project.
Then open pom.xml and add dependencies for Spring Web, Thymeleaf, Bootstrap, Jquery:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>4.6.2</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.6.1</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator-core</artifactId>
</dependency>
Or you can visit following tutorial for base project and Github source code:
Thymeleaf File Upload with Spring Boot
Create Service for File Storage
First we need an interface that will be autowired in the Controller.
In service folder, create FilesStorageService
interface like following code:
service/FilesStorageService.java
package com.bezkoder.spring.thymeleaf.file.upload.service;
import java.nio.file.Path;
import java.util.stream.Stream;
import org.springframework.core.io.Resource;
import org.springframework.web.multipart.MultipartFile;
public interface FilesStorageService {
public void init();
public void save(MultipartFile file);
public Resource load(String filename);
public boolean delete(String filename);
public void deleteAll();
public Stream<Path> loadAll();
}
Now we create implementation of the interface and override the method: boolean delete(String filename)
.
service/FilesStorageServiceImpl.java
package com.bezkoder.spring.thymeleaf.file.upload.service;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
// ...
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.util.FileSystemUtils;
import org.springframework.web.multipart.MultipartFile;
@Service
public class FilesStorageServiceImpl implements FilesStorageService {
private final Path root = Paths.get("uploads");
@Override
public void init() {
try {
Files.createDirectories(root);
} catch (IOException e) {
throw new RuntimeException("Could not initialize folder for upload!");
}
}
@Override
public void save(MultipartFile file) {
// ...
}
@Override
public Resource load(String filename) {
// ...
}
@Override
public boolean delete(String filename) {
try {
Path file = root.resolve(filename);
return Files.deleteIfExists(file);
} catch (IOException e) {
throw new RuntimeException("Error: " + e.getMessage());
}
}
@Override
public void deleteAll() {
FileSystemUtils.deleteRecursively(root.toFile());
}
@Override
public Stream<Path> loadAll() {
// ...
}
}
delete()
method receives the filename
parameter, converts a given that file string to a Path
object using Path.resolve()
.
Then we use static method Files.deleteIfExists()
to delete that file by its corresponding Path
object.
Files.deleteIfExists()
will return:
true
if the file was deleted successfully.false
if the file cannot be deleted because it does not exist
Setup the Template
In src/main/resources folder, open files.html and add Bootstrap Modal with some lines of Jquery script for delete feature:
files.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0" />
<title>BezKoder - Thymeleaf File Upload/Delete example</title>
<link rel="stylesheet" type="text/css" th:href="@{/webjars/bootstrap/css/bootstrap.min.css}" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"
integrity="sha512-xh6O/CkQoPOWDdYTDqeRdPCVd1SpvCA9XXcUnZS2FmJNp1coAFzvtCN9BmamE+4aHK8yyUHUSCcJHgXloTyT2A=="
crossorigin="anonymous" referrerpolicy="no-referrer" />
<script type="text/javascript" th:src="@{/webjars/jquery/jquery.min.js}"></script>
<script type="text/javascript" th:src="@{/webjars/bootstrap/js/bootstrap.min.js}"></script>
</head>
<body>
<div th:replace="fragments/header :: header"></div>
<div class="container-fluid" style="max-width: 600px; margin: 0 auto;">
<h2 class="text-center">List of Files</h2>
<div th:if="${files.size() > 0}">
<table class="table table-hover">
<thead class="thead-light">
<tr>
<th scope="col">File Name</th>
<th scope="col">Link</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody>
<tr th:each="file : ${files}">
<td>[[${file.name}]]</td>
<td><a th:href="@{${file.url}}">Download</a></td>
<td>
<a th:href="@{'/files/delete/' + ${file.name}}" th:fileName="${file.name}" id="btnDelete"
title="Delete this file" class="fa-regular fa-trash-can icon-dark btn-delete"></a>
</td>
</tr>
</tbody>
</table>
</div>
<div th:unless="${files.size() > 0}">
<span>No files found!</span>
</div>
</div>
<div class="modal fade text-center" id="confirmModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Delete Confirmation</h5>
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<span id="confirmText"></span>
</div>
<div class="modal-footer">
<a type="button" id="yesBtn" class="btn btn-danger">Yes</a>
<button type="button" class="btn btn-secondary" data-dismiss="modal">No</button>
</div>
</div>
</div>
</div>
<div th:replace="fragments/footer :: footer"></div>
<script type="text/javascript">
$(document).ready(function () {
$(".btn-delete").on("click", function (e) {
e.preventDefault();
link = $(this);
fileName = link.attr("fileName");
$("#yesBtn").attr("href", link.attr("href"));
$("#confirmText").html("Do you want to delete the File: \<strong\>" + fileName + "\<\/strong\>?");
$("#confirmModal").modal();
});
});
</script>
</body>
</html>
Create Controller for Delete File
In controller package, we create FileController
.
controller/FileController.java
package com.bezkoder.spring.thymeleaf.file.upload.controller;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.bezkoder.spring.thymeleaf.file.upload.model.FileInfo;
import com.bezkoder.spring.thymeleaf.file.upload.service.FilesStorageService;
@Controller
public class FileController {
@Autowired
FilesStorageService storageService;
@GetMapping("/")
public String homepage() {
return "redirect:/files";
}
// ...
@GetMapping("/files")
public String getListFiles(Model model) {
List<FileInfo> fileInfos = storageService.loadAll().map(path -> {
String filename = path.getFileName().toString();
String url = MvcUriComponentsBuilder
.fromMethodName(FileController.class, "getFile", path.getFileName().toString()).build().toString();
return new FileInfo(filename, url);
}).collect(Collectors.toList());
model.addAttribute("files", fileInfos);
return "files";
}
@GetMapping("/files/{filename:.+}")
public ResponseEntity<Resource> getFile(@PathVariable String filename) {
Resource file = storageService.load(filename);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"").body(file);
}
@GetMapping("/files/delete/{filename:.+}")
public String deleteFile(@PathVariable String filename, Model model, RedirectAttributes redirectAttributes) {
try {
boolean existed = storageService.delete(filename);
if (existed) {
redirectAttributes.addFlashAttribute("message", "Delete the file successfully: " + filename);
} else {
redirectAttributes.addFlashAttribute("message", "The file does not exist!");
}
} catch (Exception e) {
redirectAttributes.addFlashAttribute("message",
"Could not delete the file: " + filename + ". Error: " + e.getMessage());
}
return "redirect:/files";
}
}
– @Controller
annotation is used to define a controller.
– @GetMapping
annotation is for mapping HTTP GET & POST requests onto specific handler methods and returning appropriate template files.
– We use @Autowired
to inject implementation of FilesStorageService
bean to local variable.
Run the Spring Boot Delete File example
Run Spring Boot application with command: mvn spring-boot:run
.
Source Code
You can find the complete source code for this tutorial on Github.
Conclusion
Today we’ve learned how to create Spring Boot Delete File example with Thymeleaf Template Engine.
For REST API:
Spring Boot Delete File REST API example
Or upload multiple Files at once:
How to upload multiple files in Java Spring Boot
You can also know way to upload an Excel/CSV file and store the content in MySQL database with the post:
– Spring Boot: Upload/Import Excel file data into MySQL Database
– Spring Boot: Upload/Import CSV file data into MySQL Database
If you want to store files in database like this:
You can find instruction at:
Spring Boot Upload/Download File to/from Database example
Happy Learning! See you again.
Further Reading
– Spring Boot Thymeleaf CRUD example
– Spring Boot Thymeleaf Pagination and Sorting example
– Spring Boot @ControllerAdvice & @ExceptionHandler example
– @RestControllerAdvice example in Spring Boot
– Spring Boot Unit Test for JPA Repository
– Spring Boot Unit Test for Rest Controller
– Deploy Spring Boot App on AWS – Elastic Beanstalk
Fullstack:
– Angular + Spring Boot: File upload example
– React + Spring Boot: File upload example
Associations:
– Spring Boot One To One example with JPA, Hibernate
– Spring Boot One To Many example with JPA, Hibernate
– Spring Boot Many to Many example with JPA, Hibernate