plugins {
id 'org.springframework.boot' version '2.3.3.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'
}
Multipart file upload with RestTemplate
Upasana | September 05, 2020 | 4 min read | 6,151 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.x for this tutorial along with Gradle build script.
We will cover two topics here:
-
Creating a multipart file upload controller
-
Creating RestTemplate client for file upload
Part 1. Multipart file upload Controller
We will create a sample Spring Boot project using https://start.spring.io and edit the build.gradle for the following changes:
Now we need to configure Spring Boot for file upload using 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.
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:
- Spring Webclient multipart file upload
- Spring Boot multipart file upload server
- S3 File upload & download with AWS Java SDK v2
- Download a file using Spring RestTemplate
- Spring RestTemplate Basic Authentication
- SendGrid Attachments with Spring Boot
- Dialoglfow fulfillment with Spring Boot