I have the following code for a method thats supposed to return a file for download. The path variables are used to navigate to a specific file on the filesystem.
#GetMapping("/files/{username}/{docId}/{revisionNo}/{filename:.}")
#ResponseBody
public ResponseEntity<Resource> serveFile (#PathVariable("username") String username,
#PathVariable("docId") String docId,
#PathVariable("revisionNo") String revisionNo,
#PathVariable("filename") String filename)
{
System.out.println("Serve file firing"); // for debug
String filepath = username + "/" + docId + "/" + revisionNo + "/" + filename;
Resource file = storageService.loadAsResource(filepath); // this method works fine
return ResponseEntity
.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\""+file.getFilename()+"\"")
.body(file);
}
However when I start the server and go to "http://localhost:8080/files/admin/0/0/Capture1.PNG" I get a 404 error and no download. The debug println on line 9 doesn't print which would indicate this method is not being triggered.
For context this similar code does work correctly although it doesn't use the filesystem hierarchy i need and only returns files in the root folder.
#GetMapping("/files/{filename:.+}")
#ResponseBody
public ResponseEntity<Resource> serveFile(#PathVariable String filename) {
Resource file = storageService.loadAsResource(filename);
return ResponseEntity
.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\""+file.getFilename()+"\"")
.body(file);
}
I think then it must be to do with how I've used the path variables but all the research I've done indicates that its correct...running out of time to fix please help!
Related
I have an unusual task. I have to download the file and immediately force my browser to save it locally to disk?
Below, what I have written so far
#PostMapping("/uploadFile")
public String uploadFile(#RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes, Model model) {
if (file.isEmpty()) {
redirectAttributes.addFlashAttribute("errorMessage", "No file to upload.");
return "index";
}
if(getExtension(file.getOriginalFilename()).equals("XLS") || getExtension(file.getOriginalFilename()).equals("XLSX")) {
Path copyLocation = Paths
.get(UPLOAD_DIR + File.separator + StringUtils.cleanPath(file.getName()));
try {
Files.copy(file.getInputStream(), copyLocation, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
e.printStackTrace();
}
redirectAttributes.addFlashAttribute("successMessage", "File upload successfully, uploaded file name: " + file.getOriginalFilename());
}
return "response";
}
Well great, but you could show what you already have and write exactly what you have a problem with. Can't set the content disposition? Fine, but then you could show what you already have and write exactly what you have a problem with. Can't set the content disposition?
#PostMapping(value = "/", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<Resource> handleFileUpload(#RequestParam("file") MultipartFile file) {
return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=dupa.xlsx").body(file.getResource());
}
Instead of returning String (view in this case I assume) you can change your endpoint to return byte array with the file content
public #ResponseBody byte[] uploadFile(
You should also provide configuration to the #PostMapping with the media type of the file if you know what kind it's going to be.
#PostMapping(value = "/uploadFile", produces = MediaType.IMAGE_JPEG_VALUE)
Another solution is to return ResponseEntity. The documentation has two examples for it (https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/ResponseEntity.html)
I have problem with upload file to local WebDav. So far i have:
public interface IStorageService {
URI SaveFile(String filename, InputStream inputStream);
}
#Component
public class LocalStorageService implements IStorageService {
#Value( "C:\temp" )
private String filestorePath;
public URI SaveFile(String filename, InputStream inputStream) {
var rootLocation = Paths.get(filestorePath);
var filePath = rootLocation.resolve(filename);
try {
Files.copy(inputStream, filePath);
} catch (IOException e) {
throw new RuntimeException("Failure save file to " + filename + " in " + filestorePath + "." + e.getMessage(), e);
}
return filePath.toUri();
}
}
and controller
private final DocumentService documentService;
public DocumentController(DocumentService documentService) {
this.documentService = documentService;
}
#RequestMapping(method = RequestMethod.POST)
public DocumentModel handleFileUpload(#RequestParam("file") MultipartFile file) throws IOException {
return documentService.handleFileUpload(file.getOriginalFilename(), file.getInputStream());
}
And it is works correctly, the file is uploaded to C:/temp...
Now I would like to do the same but upload file to local WebDav. When i change in #Value "C:\temp to "http://localhost" (this is ma webdav location) i have:
invalidpathexception: illegal char <:> at index 4: http://localhost
or when I declare http//localhost without <:>
nosuchfileexception: http\localhost
How can I write my code to upload file directly to WebDav.
Parameters of SaveFile method cannot be changed, I need do it with Name as String and InputStream.
I tried with Sardine but to no avail. Could someone help me, give any tips or maybe suggestion of code ?
Greetings !
You can get the path where your web app/ war/ servlet / controllers are deployed :
ServletContext context = getContext();
String fullPath = context.getRealPath("/WEB-INF/test/foo.txt");
For a Spring project, in controller
'#Autowired
'ServletContext context;
And in controller method :
'String uploadPath = context.getRealPath("") + File.separator + UPLOAD_DIRECTORY;
And the real file name, but what if a user uploads same file twice or 2 users upload file with same name?
Better to put in sub directory with user id/ user name and maybe date time or some other identifier like TXN id + some fixed text like
' String fileName = context.getRealPath("") + File.separator + userId + readlName + "xyz."
extnFromMimeType;
And store the path in data base for this transaction/ user as per your busibess use case.
if mime type is image/PMG then extnFromMimeType will be "png"; if jpeg or jpg then "jpg"
See
File path to resource in our war/WEB-INF folder?
how to get getServletContext() in spring mvc Controller
In Spring MVC, how can I set the mime type header when using #ResponseBody
https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
If can be many images per user/ transaction can also use createTemp File to get a unique file name
using a UUID also possible ... https://stackoverflow.com/a/1293712/1643558 or a large random number
I am a beginner programmer, help with the implementation of uploading a text file via rest-api java.
I have already implemented the simplest action - unload a file from the server, here is my code:
#GetMapping(value = "/file/{filename:.+}")
public ResponseEntity<Resource> unloadFile(#PathVariable String filename) {
Resource file = storageService.loadAsResource(filename);
return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + file.getFilename() + "\"").body(file);
}
I can test the file unload by simply following the link!
I cannot test the upload. I find it difficult to write tests. Please tell me if I got a working code and maybe there is a better way to upload. My code upload:
#PostMapping(value = "/file")
public ResponseEntity<MultipartFile> uploadFile(MultipartFile file) {
storageService.store(file);
return ResponseEntity.ok().body(file);
}
Thank you so much!
To upload the file/files using spring boot application we use same method that we had for servlet containers. In your controller
#PostMapping("/uploadFile")
public ResponseEntity<Object> uploadFile(#RequestParam("file") MultipartFile file) {
String fileName = yourStorageService.storeFile(file);
String = ServletUriComponentsBuilder.fromCurrentContextPath()
.path("/downloadFile/")
.path(fileName)
.toUriString();
//You can even generate download links.
return new ResponseEntity<Object>(HttpStatus.Ok, "Uploaded", fileDownloadUri);
}
To download the files:
#GetMapping("/downloadFile/{fileName}")
public ResponseEntity<Resource> downloadFile(#PathVariable String fileName, HttpServletRequest request) {
// Load file as Resource from DB or local
Resource resource = fileStorageService.loadFileAsResource(fileName);
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(contentType))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
.body(resource);
For #PostMapping(value = "/file") endpoint , its best to return a success/error status instead of returning the file,if file is larger ..it takes time to return back.
Better to return success state. 200 ok.
i want to make a rest api controller (spring boot) that when petitioned with a get will allow me to download an excel file. currently i have this endpoint:
#RequestMapping(value = "/download.xls", method = RequestMethod.GET)
public ResponseEntity Survey_Reports(#RequestParam(value = "evaluated") String evaluated){
return surveyService.getSurveysFile(evaluated);
}
wich ultimately calls to this method:
public static ResponseEntity getDownloadResponse() {
File file2Upload = new File("Survey_Reports.xls");
Path path = Paths.get(file2Upload.getAbsolutePath());
ByteArrayResource resource = null;
try {
resource = new ByteArrayResource(Files.readAllBytes(path));
} catch (IOException e) {
logger.error("there was an error getting the file bytes ", e);
}
return ResponseEntity.ok()
.contentLength(file2Upload.length())
//this line doesnt seem to work as i set the file format in the controller request mapping
.contentType(MediaType.parseMediaType("application/vnd.ms-excel"))
.body(resource);
}
everything seems to work semi-fine as i get the download.xls(as the mapping) file correclty, but now i want to make the downloaded file have some specific name like: evaluatedName.xls or userDateEndDate.xls or some other stuff, is there a way to edit the response entity to do so? so that i dont have to name the mapping "download.xls"
In context of HttpServletResponse response you can do this like this
response.setContentType("application/csv");
response.setHeader("Content-Disposition", "attachment; filename=" + csvName);
and for ResponseEntity i assume you can use something like this:
ResponseEntity.ok().header("Content-Disposition","attachment; filename=" + csvName );
I'm attempting to serve local or proxy files via my Java application.
With something like this
#ResponseBody
#RequestMapping(value = "/file/{file}", method = RequestMethod.GET)
public void doGet(HttpServletRequest request, HttpServletResponse response,#PathVariable("file") String f) throws IOException {
String filename = URLDecoder.decode(f, "UTF-8");
File file = new File("resources/files/", filename);
response.setHeader("Content-Type", "video/mp4");
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-Disposition", "inline; filename=\"" + file.getName() + "\"");
Files.copy(file.toPath(), response.getOutputStream());
}
With an example URL such as
example.com/file/out2KP2_1.mp4
I'm getting the error:
Problem accessing /file/out2KP2_1.mp4. Reason:
resources\files\out2KP2_1 Caused by:
java.nio.file.NoSuchFileException: resources\files\out2KP2_1 at
sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:79)
If I add a trailing / to the url and requestMapping, it works, but on iOS and a few other places the video player doesn't seem to like loading a file with a trailing slash so it doesn't suit my purposes.
Any help appriciated.
Thanks for the mark down. Take it you didn't know the answer!?
It's a problem with Spring, you have to add :.+ to the file URL variable
i.e. #RequestMapping(value = "/file/{file:.+}", method = RequestMethod.GET)