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