THE VISTA
I use the html part with a simple form like this:
<form th:action="@{/form}" method="post" enctype="multipart/form-data">
<input type="file" name="file" class="form-control">
</form>
CONTROLLER
And in the controller you receive it this way:
@PostMapping("/form")
public String guardar(Map<String, Object> model,
@RequestParam("file") MultipartFile foto, RedirectAttributes flash, SessionStatus status) {
// ... AQUI TUS OPERACIONES DE GRABADO, MODIFICADO, ETC..
return "redirect:/listar";
}
SERVICE
The interface for that of the changes that are required later:
public interface IUploadFileService {
public Resource load(String filename) throws MalformedURLException;
public String copy(MultipartFile file) throws IOException;
public boolean delete(String filename);
public void deleteAll();
public void init() throws IOException;
}
This is the service I have prepared for uploading files.
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;
import org.slf4j.LoggerFactory;
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 UploadFileServiceImpl implements IUploadFileService {
private final static String UPLOADS_FOLDER = "upload";
private final org.slf4j.Logger log = LoggerFactory.getLogger(getClass());
@Override
public Resource load(String filename) throws MalformedURLException {
Path pathFoto = getPath(filename);
log.info("pathFoto: " + pathFoto);
Resource recurso = null;
recurso = new UrlResource(pathFoto.toUri());
if (!recurso.exists() || !recurso.isReadable()) {
throw new RuntimeException("No se puede cargar la imagen: " + pathFoto.toString());
}
return recurso;
}
@Override
public String copy(MultipartFile file) throws IOException {
String uniqueFilename = UUID.randomUUID().toString() + "_" + file.getOriginalFilename();
Path rootPath = Paths.get(UPLOADS_FOLDER).resolve(uniqueFilename);
log.info("rootPath:" + rootPath);
Files.copy(file.getInputStream(), rootPath);
return uniqueFilename;
}
@Override
public boolean delete(String filename) {
Path rootPath = getPath(filename);
File archivo = rootPath.toFile();
if (archivo.exists() && archivo.canRead()) {
if (archivo.delete()) {
return true;
}
}
return false;
}
public Path getPath(String filename) {
return Paths.get(UPLOADS_FOLDER).resolve(filename).toAbsolutePath();
}
@Override
public void deleteAll() {
FileSystemUtils.deleteRecursively(Paths.get(UPLOADS_FOLDER).toFile());
}
@Override
public void init() throws IOException {
Files.createDirectories(Paths.get(UPLOADS_FOLDER));
}
}
DEVELOPMENT CONFIGURATION.
This configuration is so that while you are doing tests the files are deleted every time you restart the server. CARE FOR PRODUCTION ENVIRONMENTS
@SpringBootApplication
public class SpringBootDataJpaApplication implements CommandLineRunner {
@Autowired
IUploadFileService uploadFileService;
public static void main(String[] args) {
SpringApplication.run(SpringBootDataJpaApplication.class, args);
}
@Override
public void run(String... args)throws Exception{
uploadFileService.deleteAll();
uploadFileService.init();
}
}
SOME CLARIFICATIONS
It's actually very simple with the service. You only have to call the service in your controller with @Autowired
for the injection of dependencies (xP) and execute your validations.
The operations are obvious:
-
load(String filename)
allows you to get the file from the server when it is already loaded.
-
copy (MultipartFile file)
copies the MultipartFile
that you got from the form to the server in the folder defined in UPLOADS_FOLDER
.
-
delete(String filename)
removes the file from the server if it exists.
In my case I am working with photos, hence many of the names refer to photos but it is useful for any file. The type validation part is already up to you.
FINAL RECOMMENDATIONS
I recommend you do all the tests first in an html form. This way you will not have to be thinking about JS and the backend. The change afterwards is easy.
I trust you are using spring-boot with annotations and not xml.