File Upload in Spring MVC using RestTemplate with ByteArrayResource & FileSystemResource

Carvia Tech | July 11, 2019 | | 24 views


In this short tutorial we will learn how to do file upload to a spring mvc endpoint using RestTemplate via ByteArrayResource & FileSystemResource. We will be using Spring Boot 2.1.x for this tutorial along with Gradle build script.

Part 1. Spring RestController to handle file upload

We will create a sample Spring Boot project using https://start.spring.io and edit the build.gradle for the following changes:

build.gradle
plugins {
	id 'org.springframework.boot' version '2.1.6.RELEASE'
	id 'java'
}

apply plugin: 'io.spring.dependency-management'

group = 'com.shunya'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

Now we need to configure Spring Boot for file upload using application.yml

/src/main/resources/application.yml
spring:
  application:
    name: file-upload

  main:
    web-application-type: servlet

  mvc:
    async:
      request-timeout: -1
  servlet:
    multipart:
      max-file-size: 20MB
      max-request-size: 20MB
      enabled: true
      file-size-threshold: 1MB
      location: ${java.io.tmpdir} (1)
1 Intermediate location for storing file uploads on server side

Now we are all set to write a simple file upload controller that will accept a multi-part file and save it on server side.

/com/shunya/tutorials/UploadController.java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;

@RestController
@RequestMapping("/upload")
public class UploadController {

    private static final Logger logger = LoggerFactory.getLogger(UploadController.class);

    @RequestMapping(method = RequestMethod.POST)
    public ServiceResponse handleFileUpload(@RequestParam("user-file") MultipartFile multipartFile) throws IOException {
        String name = multipartFile.getOriginalFilename();
        logger.info("File name: " + name);
        //Ideally you shall read bytes using multipartFile.getInputStream() and store it appropriately
        byte[] bytes = multipartFile.getBytes();
        logger.info("File uploaded content: {}", new String(bytes));
        ServiceResponse response = new ServiceResponse();
        response.setSuccess(true);
        return response;
    }
}

Part 2. Using ByteArrayResource with RestTemplate for file upload

We can use either FileSystemResource or ByteArrayResource for fileupload with RestTemplate, we will cover both one by one.

In the below code snippet, we are writing a Spring Boot Junit Testcase that will start the container and do the file upload using RestTemplate.

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.*;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

import static java.util.Arrays.asList;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsEqual.equalTo;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ApplicationTests {

	@Autowired
	private TestRestTemplate testRestTemplate;  (3)

	@Test
	public void testFileUploadByteArrayResource() {
		String fileName = "test.txt";
		byte[] fileContent = "this is file content".getBytes();

		HttpHeaders parts = new HttpHeaders();  (1)
		parts.setContentType(MediaType.TEXT_PLAIN);
		final ByteArrayResource byteArrayResource = new ByteArrayResource(fileContent) {
			@Override
			public String getFilename() {   (2)
				return fileName;
			}
		};
		final HttpEntity<ByteArrayResource> partsEntity = new HttpEntity<>(byteArrayResource, parts);

		HttpHeaders headers = new HttpHeaders();
		headers.setAccept(asList(MediaType.APPLICATION_JSON));
		headers.setContentType(MediaType.MULTIPART_FORM_DATA);

		MultiValueMap<String, Object> requestMap = new LinkedMultiValueMap<>();
		requestMap.add("user-file", partsEntity);

		final ParameterizedTypeReference<ServiceResponse> typeReference = new ParameterizedTypeReference<ServiceResponse>() {
		};

		final ResponseEntity<ServiceResponse> exchange = testRestTemplate.exchange("/upload", HttpMethod.POST, new HttpEntity<>(requestMap, headers), typeReference);
		if(exchange.getStatusCode().is2xxSuccessful()) {
			System.out.println("File uploaded = " + exchange.getBody().isSuccess());
		}
		assertThat(exchange.getStatusCode().is2xxSuccessful(), equalTo(true));
		assertThat(exchange.getBody().isSuccess(), equalTo(true));
	}

}
1 We are setting mime type for individual files that we add to the request.
2 Overriding getFilename() is necessary step here, because we need it on server side. Overriding this method is not required if we use FileSystemResource.
3 We can use either TestRestTemplate of RestTemplate. For production code, you shall use RestTemplate only.

Part 3. Using FileSystemResource with RestTemplate for file upload

In this last section, we will be using FileSystemResource instead of ByteArrayResource for handlign file upload with TestRestTemplate.

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ApplicationTests {

	@Autowired
	private TestRestTemplate testRestTemplate;

	@Test
	public void testFileUploadFileSystemResource() throws IOException {
		byte[] fileContent = "this is file content".getBytes();

		HttpHeaders headers = new HttpHeaders();
		headers.setAccept(asList(MediaType.APPLICATION_JSON));
		headers.setContentType(MediaType.MULTIPART_FORM_DATA);

		MultiValueMap<String, Object> requestMap = new LinkedMultiValueMap<>();
		requestMap.add("user-file", createTempFileResource(fileContent));

		final ParameterizedTypeReference<ServiceResponse> typeReference = new ParameterizedTypeReference<ServiceResponse>() {
		};

		final ResponseEntity<ServiceResponse> exchange = testRestTemplate.exchange("/upload", HttpMethod.POST, new HttpEntity<>(requestMap, headers), typeReference);
		if(exchange.getStatusCode().is2xxSuccessful()) {
			System.out.println("File uploaded = " + exchange.getBody().isSuccess());
		}
		assertThat(exchange.getStatusCode().is2xxSuccessful(), equalTo(true));
		assertThat(exchange.getBody().isSuccess(), equalTo(true));
	}

	static Resource createTempFileResource(byte [] content) throws IOException {
		Path tempFile = Files.createTempFile("upload-file", ".txt");
		Files.write(tempFile, content);
		return new FileSystemResource(tempFile.toFile());
	}

}

That’s it.


Top articles in this category:
  1. How to prevent duplicate form submission in Spring MVC
  2. How will you test web layer in Spring Boot using WebMvcTest annotation?
  3. Securing Spring MVC REST endpoint using Basic Auth
  4. Running Spring Boot app as a service in unix
  5. Custom banner in spring boot application
  6. Setting a Random Port in Spring Boot Application at startup
  7. Spring Boot 2.0 Reactive Web Performance Metrics



Find more on this topic:
Spring Framework image
Spring Framework

Spring Framework - MVC, Dependency Injection, Spring Hibernate, Spring Data JPA, Spring Boot and Spring Cloud for Microservices Architecture.

Last updated 1 week ago


Recommended books for interview preparation:

This website uses cookies to ensure you get the best experience on our website. more info