file upload Spring Boot
This commit is contained in:
@@ -0,0 +1,75 @@
|
|||||||
|
package com.javadevjournal.controller;
|
||||||
|
|
||||||
|
import com.javadevjournal.data.FileMetaData;
|
||||||
|
import com.javadevjournal.exception.FileStorageException;
|
||||||
|
import com.javadevjournal.service.FileStorageService;
|
||||||
|
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.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class FileUploadController extends PageController{
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
FileStorageService fileStorageService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller to display the file upload form on the frontend.
|
||||||
|
* @param model
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@GetMapping("/upload-file")
|
||||||
|
public String uploadFile(final Model model){
|
||||||
|
return "uploadFile";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST method to accept the incoming file in the application.This method is designed to accept
|
||||||
|
* only 1 file at a time.
|
||||||
|
* @param file
|
||||||
|
* @param redirectAttributes
|
||||||
|
* @return succes page
|
||||||
|
*/
|
||||||
|
@PostMapping("/upload-file")
|
||||||
|
public String uploadFile(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes, Model model){
|
||||||
|
|
||||||
|
try {
|
||||||
|
FileMetaData data = fileStorageService.store(file);
|
||||||
|
data.setUrl(fileDownloadUrl(data.getFileName(),"/media/download/"));
|
||||||
|
model.addAttribute("uploadedFile", data);
|
||||||
|
|
||||||
|
} catch (FileStorageException e) {
|
||||||
|
model.addAttribute("error", "Unable to store the file");
|
||||||
|
return "uploadFile";
|
||||||
|
}
|
||||||
|
return "uploadFile";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller to allow customer to download the file by passing the file name as the
|
||||||
|
* request URL.
|
||||||
|
* @param fileName
|
||||||
|
* @param response
|
||||||
|
* @return
|
||||||
|
* @throws FileNotFoundException
|
||||||
|
*/
|
||||||
|
@GetMapping("/media/download/{fileName:.+}")
|
||||||
|
public ResponseEntity<Resource> downloadFIle(@PathVariable String fileName, final HttpServletResponse response) throws FileNotFoundException {
|
||||||
|
FileMetaData fileData= fileStorageService.getFile(fileName);
|
||||||
|
response.setContentType(fileData.getMime());
|
||||||
|
return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION,
|
||||||
|
"attachment; filename=\"" + fileName + "\"").body(fileData.getResource());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.javadevjournal.controller;
|
||||||
|
|
||||||
|
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
||||||
|
|
||||||
|
public class PageController {
|
||||||
|
|
||||||
|
public String fileDownloadUrl(final String fileName, final String baseURL){
|
||||||
|
return ServletUriComponentsBuilder.fromCurrentContextPath()
|
||||||
|
.path(baseURL)
|
||||||
|
.path(fileName).toUriString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package com.javadevjournal.controller;
|
||||||
|
|
||||||
|
import com.javadevjournal.data.FileMetaData;
|
||||||
|
import com.javadevjournal.exception.FileStorageException;
|
||||||
|
import com.javadevjournal.service.FileStorageService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1")
|
||||||
|
public class RestFileUploadController extends PageController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
FileStorageService fileStorageService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* REST controller to allow file uploading for our REST API
|
||||||
|
* @param file
|
||||||
|
* @param redirectAttributes
|
||||||
|
* @param model
|
||||||
|
* @return FileMetaData
|
||||||
|
* @throws FileStorageException
|
||||||
|
*/
|
||||||
|
@PostMapping("/upload-file")
|
||||||
|
@ResponseBody
|
||||||
|
public FileMetaData uploadFile(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes, Model model) throws FileStorageException {
|
||||||
|
FileMetaData data= fileStorageService.store(file);
|
||||||
|
data.setUrl(fileDownloadUrl(data.getFileName(),"/api/v1/media/download/"));
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rest Controller method for file download feature.
|
||||||
|
* @param fileName
|
||||||
|
* @return ResponseEntity
|
||||||
|
* @throws FileNotFoundException
|
||||||
|
*/
|
||||||
|
@GetMapping("/media/download/{fileName:.+}")
|
||||||
|
public ResponseEntity<Resource> downloadFile(@PathVariable String fileName) throws FileNotFoundException {
|
||||||
|
FileMetaData fileData= fileStorageService.getFile(fileName);
|
||||||
|
return ResponseEntity.ok()
|
||||||
|
.header(HttpHeaders.CONTENT_DISPOSITION,
|
||||||
|
"attachment; filename=\"" + fileName + "\"")
|
||||||
|
.contentType(MediaType.parseMediaType(fileData.getMime()))
|
||||||
|
.body(fileData.getResource());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package com.javadevjournal.data;
|
||||||
|
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
|
||||||
|
public class FileMetaData {
|
||||||
|
|
||||||
|
private String fileName;
|
||||||
|
private String url;
|
||||||
|
private String mime;
|
||||||
|
private long size;
|
||||||
|
private Resource resource;
|
||||||
|
|
||||||
|
public FileMetaData() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileMetaData(String fileName, String url, String mime, long size) {
|
||||||
|
this.fileName = fileName;
|
||||||
|
this.url = url;
|
||||||
|
this.mime = mime;
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFileName() {
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileName(String fileName) {
|
||||||
|
this.fileName = fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrl(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMime() {
|
||||||
|
return mime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMime(String mime) {
|
||||||
|
this.mime = mime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSize(long size) {
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Resource getResource() {
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResource(Resource resource) {
|
||||||
|
this.resource = resource;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.javadevjournal.exception;
|
||||||
|
|
||||||
|
public class FileStorageException extends Exception {
|
||||||
|
|
||||||
|
public FileStorageException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileStorageException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileStorageException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
package com.javadevjournal.service;
|
||||||
|
|
||||||
|
import com.javadevjournal.data.FileMetaData;
|
||||||
|
import com.javadevjournal.exception.FileStorageException;
|
||||||
|
import com.javadevjournal.utils.UploadFileProperties;
|
||||||
|
import org.apache.tika.detect.Detector;
|
||||||
|
import org.apache.tika.io.TikaInputStream;
|
||||||
|
import org.apache.tika.metadata.Metadata;
|
||||||
|
import org.apache.tika.mime.MediaType;
|
||||||
|
import org.apache.tika.parser.AutoDetectParser;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.UrlResource;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
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.nio.file.StandardCopyOption;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service("fileStorageService")
|
||||||
|
public class DefaultFileStorageService implements FileStorageService {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(DefaultFileStorageService.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
UploadFileProperties uploadFileProperties;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileMetaData store(MultipartFile file) throws FileStorageException {
|
||||||
|
|
||||||
|
//Normalize the path by suppressing sequences like "path/.." and inner simple dots.
|
||||||
|
String fileName = StringUtils.cleanPath(file.getOriginalFilename());
|
||||||
|
try {
|
||||||
|
// we can add additional file validation to discard invalid files
|
||||||
|
Path uploadDir = getUploadDirLocation().resolve(fileName);
|
||||||
|
|
||||||
|
//copy the file to the upload directory,it will replace any file with same name.
|
||||||
|
Files.copy(file.getInputStream(), uploadDir, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
|
||||||
|
FileMetaData fileData = new FileMetaData();
|
||||||
|
fileData.setFileName(fileName);
|
||||||
|
fileData.setSize(file.getSize());
|
||||||
|
fileData.setMime(file.getContentType());
|
||||||
|
return fileData;
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.error("unable to cpy file to the target location {}", e);
|
||||||
|
throw new FileStorageException("Unable to store file " + fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read all files and return as list of @FileMetaData
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<Path> getAllFiles() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to return the file as @Resource for the download.It read the file from the file system
|
||||||
|
* and return it as @Resource
|
||||||
|
* @param fileName
|
||||||
|
* @return FileMetaData
|
||||||
|
* @throws FileNotFoundException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public FileMetaData getFile(String fileName) throws FileNotFoundException {
|
||||||
|
Path path = getUploadDirLocation().resolve(fileName).normalize();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Resource resource = new UrlResource(path.toUri());
|
||||||
|
|
||||||
|
if(resource.exists()){
|
||||||
|
Metadata metadata = getFileMetaDataInfo(resource);
|
||||||
|
FileMetaData fileMetaData = new FileMetaData();
|
||||||
|
fileMetaData.setResource(resource);
|
||||||
|
fileMetaData.setFileName(fileName);
|
||||||
|
fileMetaData.setSize(metadata.size());
|
||||||
|
fileMetaData.setMime(metadata.get(Metadata.CONTENT_TYPE));
|
||||||
|
return fileMetaData;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
throw new FileNotFoundException("Not able to find file");
|
||||||
|
}
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
throw new FileNotFoundException("Not able to find file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the upload directory location based on the application.properties configurations
|
||||||
|
*
|
||||||
|
* @return Path
|
||||||
|
*/
|
||||||
|
private Path getUploadDirLocation() {
|
||||||
|
return Paths.get(uploadFileProperties.getUploadDir()).toAbsolutePath().normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to get the file meta-data using Apache Tikka corre library.JDK also provide
|
||||||
|
* way to read meta-data information but it's very limited and have lot of issues.
|
||||||
|
* @param resource
|
||||||
|
* @return Metadata
|
||||||
|
*/
|
||||||
|
private Metadata getFileMetaDataInfo(Resource resource){
|
||||||
|
AutoDetectParser parser = new AutoDetectParser();
|
||||||
|
Detector detector = parser.getDetector();
|
||||||
|
Metadata metadata = new Metadata();
|
||||||
|
try {
|
||||||
|
metadata.set(Metadata.RESOURCE_NAME_KEY, resource.getFile().getName());
|
||||||
|
TikaInputStream stream = TikaInputStream.get(resource.getInputStream());
|
||||||
|
MediaType mediaType = detector.detect(stream,metadata);
|
||||||
|
metadata.set(Metadata.CONTENT_TYPE, mediaType.toString());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
//fallback to default content type
|
||||||
|
metadata.set(Metadata.CONTENT_TYPE, "application/octet-stream");
|
||||||
|
|
||||||
|
}
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.javadevjournal.service;
|
||||||
|
|
||||||
|
import com.javadevjournal.data.FileMetaData;
|
||||||
|
import com.javadevjournal.exception.FileStorageException;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface FileStorageService {
|
||||||
|
|
||||||
|
FileMetaData store(MultipartFile file) throws FileStorageException;
|
||||||
|
List<Path> getAllFiles();
|
||||||
|
FileMetaData getFile(String fileName) throws FileNotFoundException;
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.javadevjournal.utils;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "file")
|
||||||
|
@EnableConfigurationProperties
|
||||||
|
public class UploadFileProperties {
|
||||||
|
|
||||||
|
private String uploadDir;
|
||||||
|
|
||||||
|
public String getUploadDir() {
|
||||||
|
return uploadDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUploadDir(String uploadDir) {
|
||||||
|
this.uploadDir = uploadDir;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<body>
|
||||||
|
<div th:if="${uploadedFile}">
|
||||||
|
<h2> Uploaded File Details </h2>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td th:text="${uploadedFile.fileName}">File Name</td><br>
|
||||||
|
<td th:text="${uploadedFile.mime}">File Type:</td><br>
|
||||||
|
<td th:text="${uploadedFile.url}">URL :</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2> Uploaded New File </h2>
|
||||||
|
<form method="POST" enctype="multipart/form-data" action="/upload-file">
|
||||||
|
<table>
|
||||||
|
<tr><td>File to upload 1:</td><td><input type="file" name="file" /></td></tr>
|
||||||
|
|
||||||
|
<tr><td></td><td><input type="submit" value="Upload" /></td></tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user