opencodez

Simplest and Easy way to Upload and Download Files in Java with Spring Boot

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

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