Uploading and Downloading Files is one of the core functionality that any Enterprise Application wants to incorporate. In this article, we will see How to Upload and Download Files in Java with Spring Boot.
Softwares used
- Spring Boot 2.0.3.RELEASE
- Thymeleaf
- Java 8
- Maven
- Eclipse
Maven Dependencies
Below are the key dependencies that we are using.
xpropertiesx xproject.build.sourceEncodingxUTF-8x/project.build.sourceEncodingx xproject.reporting.outputEncodingxUTF-8x/project.reporting.outputEncodingx xjava.versionx1.8x/java.versionx xmaven-jar-plugin.versionx2.6x/maven-jar-plugin.versionx x/propertiesx xdependenciesx xdependencyx xgroupIdxorg.springframework.bootx/groupIdx xartifactIdxspring-boot-starter-thymeleafx/artifactIdx x/dependencyx xdependencyx xgroupIdxorg.springframework.bootx/groupIdx xartifactIdxspring-boot-starter-webx/artifactIdx x/dependencyx xdependencyx xgroupIdxorg.springframework.bootx/groupIdx xartifactIdxspring-boot-starter-testx/artifactIdx xscopextestx/scopex x/dependencyx x!--WebJars --x xdependencyx xgroupIdxorg.webjarsx/groupIdx xartifactIdxbootstrapx/artifactIdx xversionx3.3.6x/versionx x/dependencyx xdependencyx xgroupIdxorg.webjarsx/groupIdx xartifactIdxjqueryx/artifactIdx xversionx2.1.4x/versionx x/dependencyx x!--/WebJars --x x/dependenciesx
Our code is built on top of Web Starter Application. We are using WebJars for Bootstrap and Jquery.
At the core of this application will be our service class x FileSystemStorageService.java. We will look at each of its functions in the rest of the article.
Initialization
@PostConstruct public void init() { this.uploadLocation = Paths.get(Constants.UPLOAD_LOCATION); try { Files.createDirectories(uploadLocation); } catch (IOException e) { throw new RuntimeException("Could not initialize storage", e); } }
This code is executed after the service class object is created. In this init method, we try to create the directory where we want to upload our files.
Storing the file
public void store(MultipartFile file) { String filename = StringUtils.cleanPath(file.getOriginalFilename()); try { if (file.isEmpty()) { throw new RuntimeException("Failed to store empty file " + filename); } // This is a security check if (filename.contains("..")) { throw new RuntimeException("Cannot store file with relative path outside current directory " + filename); } try (InputStream inputStream = file.getInputStream()) { Files.copy(inputStream, this.uploadLocation.resolve(filename), StandardCopyOption.REPLACE_EXISTING); } } catch (IOException e) { throw new RuntimeException("Failed to store file " + filename, e); } }
This method will get a MultipartFile from Spring controller. The file name is then resolved relative to our upload directory and copied there.
File as Resource
public Resource loadAsResource(String filename) { try { Path file = uploadLocation.resolve(filename); Resource resource = new UrlResource(file.toUri()); if (resource.exists() || resource.isReadable()) { return resource; } else { throw new RuntimeException("Could not read file: " + filename); } } catch (MalformedURLException e) { throw new RuntimeException("Could not read file: " + filename, e); } }
Above code, converts a file that we want to download into a Resource. This resource is later pushed to download via the controller.
Now let us look at few controller methods which utilize above service class to achieve the functionality.
Handle File Upload
@RequestMapping(value = "/files/upload", method = RequestMethod.POST) public String handleFileUpload(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) { storageService.store(file); redirectAttributes.addFlashAttribute("message", "You successfully uploaded " + file.getOriginalFilename() + "!"); return "redirect:/"; }
Above method will kick off, when you upload a file from UI. The Spring controller receives a MultipartFile, which is then sent to storage service class.
Downloading a File
@RequestMapping(value = "/files/list", method = RequestMethod.GET) public String listFiles(Model model) { ListxPathx lodf = new ArrayListxx(); ListxHRefModelx uris = new ArrayListxx(); try { lodf = storageService.listSourceFiles(storageService.getUploadLocation()); for(Path pt : lodf) { HRefModel href = new HRefModel(); href.setHref(MvcUriComponentsBuilder .fromMethodName(UploadController.class, "serveFile", pt.getFileName().toString()) .build() .toString()); href.setHrefText(pt.getFileName().toString()); uris.add(href); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } model.addAttribute("listOfEntries", uris); return "file_list :: urlFileList"; } @GetMapping("/files/{filename:.+}") @ResponseBody public ResponseEntityxResourcex serveFile(@PathVariable String filename) { Resource file = storageService.loadAsResource(filename); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"") .body(file); }
Downloading a file is 2 step process. First, we have to list all the files in the URL form and when the user clicks on any of the links, we will send the actual file.
Listing of files uses MvcUriComponentsBuilder to prepare the URL based on the method which is going to actually serve the file for download. When a user clicks on a file name headers and attachments is sent to the client.
Demo: Upload and Download Files in Java
Notice that we are allowing only text files to be uploaded. The upload button is enabled only when a user selects text file. The code for this is available in upload.js.
Once you select a text file and click on Upload, you will see the message that file is uploaded successfully.
You can check the files which we uploaded and listed on our page are physically available on our servers.
Conclusion
In this article, we have seen how Spring Boot has made Upload and Download Files in Java easy to implement.
The complete code is available at our GitHub repo. Please feel free to download and try.
Download Code