Spring controller image download in byte[] instead base64 - java

I encountered a problem with downloading grid fs stored image via spring controller. When trying to open the downloaded file the image viewer says that it is corrupted, it turns out that the image is in base64 format.
There is the controller part:
#Override
#RequestMapping(value = "/image_download", method = RequestMethod.GET)
public ResponseEntity<byte[]> downloadImage(...) throws IOException {
final GridFSDBFile image = getImageFromGrifFs(...);
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf(image.getContentType()));
headers.setContentDispositionFormData("attachment", image.getFileName());
final byte[] content = IOUtils.toByteArray(image.getInputStream());
return new ResponseEntity<>(content, headers, HttpStatus.OK);
}
Spring version is 4.3.11.
And here are the message converters:
#Override
public void configureMessageConverters(final List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJackson2HttpMessageConverter());
converters.add(byteArrayHttpMessageConverter());
super.configureMessageConverters(converters);
}
#Bean
public ByteArrayHttpMessageConverter byteArrayHttpMessageConverter() {
final ByteArrayHttpMessageConverter arrayHttpMessageConverter = new ByteArrayHttpMessageConverter();
arrayHttpMessageConverter.setSupportedMediaTypes(getSupportedMediaTypes());
return arrayHttpMessageConverter;
}
private List<MediaType> getSupportedMediaTypes() {
final List<MediaType> list = new ArrayList<>();
list.add(MediaType.IMAGE_JPEG);
list.add(MediaType.IMAGE_PNG);
list.add(MediaType.IMAGE_GIF);
list.add(MediaType.APPLICATION_OCTET_STREAM);
return list;
}
I also tried using InputStreamResource the following way in the controller:
return ResponseEntity.ok()
.contentLength(image.getLength())
.contentType(MediaType.parseMediaType(image.getContentType()))
.body(new InputStreamResource(image.getInputStream()));
But got the exception:
Could not write content: No serializer found for class com.mongodb.gridfs.GridFSDBFile$MyInputStream
Any help appreciated. Thank you.

After I'd done some more digging I found good explanation: https://stackoverflow.com/a/44943494/2421204
And indeed adding (produces = "image/jpeg") to RequestMapping solved the issue.
#RequestMapping(value = "/image_download", method = RequestMethod.GET, produces = "image/jpeg")
The images that are downloaded are in binary.

Related

Sending file in Spring Boot

I'm creating spring boot application that send a file in body response, to this i use this code :
FileSystemResource pdfFile = new FileSystemResource(outputFile);
return ResponseEntity
.ok()
.contentLength(pdfFile.contentLength())
.contentType(MediaType.parseMediaType("application/pdf"))
.body(new ByteArrayResource(IOUtils.toByteArray(pdfFile.getInputStream())));
I'm wondering if there's any alternative way for send file other than using FileSystemResource ?
Please, If there's any suggestion, do not hesitate.
Thank You !
This is a simplified version of how I usually do it, but it does pretty much the same thing:
#RequestMapping(method = RequestMethod.GET, value = "/{id}")
public ResponseEntity<byte[]> getPdf(#PathVariable Long id) throws IOException {
final String filePath = pdfFilePathFinder.find(id);
final byte[] pdfBytes = Files.readAllBytes(Paths.get(filePath));
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("application/pdf"));
headers.setContentDispositionFormData("attachment", null);
headers.setCacheControl("no-cache");
return new ResponseEntity<>(pdfBytes, headers, HttpStatus.OK);
}

return ByteArrayResource in spring restcontroller response

I'm trying to download a file using my restController, but it always return this error :
java.io.FileNotFoundException: Byte array resource [resource loaded from byte array] cannot be resolved to URL
at org.springframework.core.io.AbstractResource.getURL(AbstractResource.java:90) ~[spring-core-4.2.2.RELEASE.jar:4.2.2.RELEASE]
then it downloads a file that has something like this :
{"byteArray":"JVBERi0xLjQKJeL....
here's my restController :
#Api("products")
#RestController
#RequestMapping("/v1/products")
public class DocumentApi extends storeApi {
#ApiOperation("GET download document")
#RequestMapping(value = "/temp", method = RequestMethod.GET)
#ResponseStatus(code = HttpStatus.OK)
public ResponseEntity<ByteArrayResource> downloadDocument(
#RequestParam(value = "id", required = true) Long idInscription) throws IOException {
String signedFilePAth = "C:/APPLIS/signedTemp/5982312957957647037_signed.pdf"
return ResponseEntity
.ok()
.contentLength(contentLength)
.contentType(
MediaType.parseMediaType("application/pdf"))
.body(new
ByteArrayResource(Files.readAllBytes(Paths.get(signedFilePAth))));
}
}
and here's my spring configuration :
protected MappingJackson2HttpMessageConverter jacksonMessageConverter() {
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
// Registering Hibernate4Module to support lazy objects
mapper.registerModule(new Hibernate4Module());
messageConverter.setObjectMapper(mapper);
return messageConverter;
}
public ByteArrayHttpMessageConverter byteArrayHttpMessageConverter() {
ByteArrayHttpMessageConverter arrayHttpMessageConverter = new ByteArrayHttpMessageConverter();
arrayHttpMessageConverter.setSupportedMediaTypes(getSupportedMediaTypes());
return arrayHttpMessageConverter;
}
private List<MediaType> getSupportedMediaTypes() {
List<MediaType> list = new ArrayList<MediaType>();
list.add(MediaType.APPLICATION_OCTET_STREAM);
list.add(MediaType.parseMediaType("application/pdf"));
return list;
}
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(jacksonMessageConverter());
converters.add(byteArrayHttpMessageConverter());
super.configureMessageConverters(converters);
}
what seems to be the problem ? how can i solve this ?
nb : I don't know if this is related, but my swagger-ui.html doesn't work (it shows a blank page) while v2/api-docs/ works fine
Try returning array of bytes:
#RequestMapping(value = "/temp", method = RequestMethod.GET)
public #ResponseBody byte[] downloadDocument(
#RequestParam(value = "id", required = true) Long idInscription) throws IOException {
FileInputStream signedFileInputStream = new FileInputStream(signedFilePAth);
byte[] doc = IOUtils.toByteArray(fis);
return doc;
}
IOUtils is from org.apache.commons.io.IOUtils.
It seems that the response content type definition is missing from your code.
The following code snippet returns with an image content which is displayed by web browser. It is a Jersy code but you can adopt it to Spring:
#GET
#Path("/{image-uuid}")
#Produces("images/jpg")
public Response getImage(#PathParam("uuid") final String uuid) throws IOException {
byte[] content = imageDao.getImage(uuid);
if (Objects.isNull(content )) {
throw new ImageNotFoundError(uuid);
}
ByteArrayInputStream stream = new ByteArrayInputStream(content);
return Response.ok(stream).build();
}

How to read Long blob from mysql in java? [duplicate]

I'm getting image data (as byte[]) from DB. How to return this image in #ResponseBody ?
EDIT
I did it without #ResponseBody using HttpServletResponse as method parameter:
#RequestMapping("/photo1")
public void photo(HttpServletResponse response) throws IOException {
response.setContentType("image/jpeg");
InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg");
IOUtils.copy(in, response.getOutputStream());
}
Using #ResponseBody with registered org.springframework.http.converter.ByteArrayHttpMessageConverter converter as #Sid said doesn't work for me :(.
#ResponseBody
#RequestMapping("/photo2")
public byte[] testphoto() throws IOException {
InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg");
return IOUtils.toByteArray(in);
}
if you are using Spring version of 3.1 or newer you can specify "produces" in #RequestMapping annotation. Example below works for me out of box. No need of register converter or anything else if you have web mvc enabled (#EnableWebMvc).
#ResponseBody
#RequestMapping(value = "/photo2", method = RequestMethod.GET, produces = MediaType.IMAGE_JPEG_VALUE)
public byte[] testphoto() throws IOException {
InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg");
return IOUtils.toByteArray(in);
}
With Spring 4.1 and above, you can return pretty much anything (such as pictures, pdfs, documents, jars, zips, etc) quite simply without any extra dependencies. For example, the following could be a method to return a user's profile picture from MongoDB GridFS:
#RequestMapping(value = "user/avatar/{userId}", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<InputStreamResource> downloadUserAvatarImage(#PathVariable Long userId) {
GridFSDBFile gridFsFile = fileService.findUserAccountAvatarById(userId);
return ResponseEntity.ok()
.contentLength(gridFsFile.getLength())
.contentType(MediaType.parseMediaType(gridFsFile.getContentType()))
.body(new InputStreamResource(gridFsFile.getInputStream()));
}
The things to note:
ResponseEntity with InputStreamResource as a return type
ResponseEntity builder style creation
With this method you dont have to worry about autowiring in the HttpServletResponse, throwing an IOException or copying stream data around.
In addition to registering a ByteArrayHttpMessageConverter, you may want to use a ResponseEntity instead of #ResponseBody. The following code works for me :
#RequestMapping("/photo2")
public ResponseEntity<byte[]> testphoto() throws IOException {
InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg");
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_PNG);
return new ResponseEntity<byte[]>(IOUtils.toByteArray(in), headers, HttpStatus.CREATED);
}
By using Spring 3.1.x and 3.2.x, this is how you should do it:
The controller method:
#RequestMapping("/photo2")
public #ResponseBody byte[] testphoto() throws IOException {
InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg");
return IOUtils.toByteArray(in);
}
And the mvc annotation in servlet-context.xml file:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>image/jpeg</value>
<value>image/png</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
In addition to a couple of answers here a few pointers (Spring 4.1).
Incase you don't have any messageconverters configured in your WebMvcConfig, having ResponseEntity inside your #ResponseBody works well.
If you do, i.e. you have a MappingJackson2HttpMessageConverter configured (like me) using the ResponseEntity returns a org.springframework.http.converter.HttpMessageNotWritableException.
The only working solution in this case is to wrap a byte[] in the #ResponseBody as follows:
#RequestMapping(value = "/get/image/{id}", method=RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE)
public #ResponseBody byte[] showImageOnId(#PathVariable("id") String id) {
byte[] b = whatEverMethodUsedToObtainBytes(id);
return b;
}
In this case do rememeber to configure the messageconverters properly (and add a ByteArrayHttpMessageConverer) in your WebMvcConfig, like so:
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(mappingJackson2HttpMessageConverter());
converters.add(byteArrayHttpMessageConverter());
}
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(objectMapper);
return converter;
}
#Bean
public ByteArrayHttpMessageConverter byteArrayHttpMessageConverter() {
ByteArrayHttpMessageConverter arrayHttpMessageConverter = new ByteArrayHttpMessageConverter();
arrayHttpMessageConverter.setSupportedMediaTypes(getSupportedMediaTypes());
return arrayHttpMessageConverter;
}
private List<MediaType> getSupportedMediaTypes() {
List<MediaType> list = new ArrayList<MediaType>();
list.add(MediaType.IMAGE_JPEG);
list.add(MediaType.IMAGE_PNG);
list.add(MediaType.APPLICATION_OCTET_STREAM);
return list;
}
I prefere this one:
private ResourceLoader resourceLoader = new DefaultResourceLoader();
#ResponseBody
#RequestMapping(value = "/{id}", produces = "image/bmp")
public Resource texture(#PathVariable("id") String id) {
return resourceLoader.getResource("classpath:images/" + id + ".bmp");
}
Change the media type to what ever image format you have.
In your application context declare a AnnotationMethodHandlerAdapter and registerByteArrayHttpMessageConverter:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<util:list>
<bean id="byteArrayMessageConverter" class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
</util:list>
</property>
</bean>
also in the handler method set appropriate content type for your response.
#RequestMapping(value = "/get-image",method = RequestMethod.GET)
public ResponseEntity<byte[]> getImage() throws IOException {
RandomAccessFile f = new RandomAccessFile("/home/vivex/apache-tomcat-7.0.59/tmpFiles/1.jpg", "r");
byte[] b = new byte[(int)f.length()];
f.readFully(b);
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_PNG);
return new ResponseEntity<byte[]>(b, headers, HttpStatus.CREATED);
}
Worked For Me.
You should specify the media type in the response. I'm using a #GetMapping annotation with produces = MediaType.IMAGE_JPEG_VALUE. #RequestMapping will work the same.
#GetMapping(value="/current/chart",produces = MediaType.IMAGE_JPEG_VALUE)
#ResponseBody
public byte[] getChart() {
return ...;
}
Without a media type, it is hard to guess what is actually returned (includes anybody who reads the code, browser and of course Spring itself). A byte[] is just not specific. The only way to determine the media type from a byte[] is sniffing and guessing around.
Providing a media type is just best practice
It's work for me in Spring 4.
#RequestMapping(value = "/image/{id}", method = RequestMethod.GET)
public void findImage(#PathVariable("id") String id, HttpServletResponse resp){
final Foto anafoto = <find object>
resp.reset();
resp.setContentType(MediaType.IMAGE_JPEG_VALUE);
resp.setContentLength(anafoto.getImage().length);
final BufferedInputStream in = new BufferedInputStream(new ByteArrayInputStream(anafoto.getImageInBytes()));
try {
FileCopyUtils.copy(in, resp.getOutputStream());
resp.flushBuffer();
} catch (final IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Non of the answers worked for me, so I've managed to do it like that:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("your content type here"));
headers.set("Content-Disposition", "attachment; filename=fileName.jpg");
headers.setContentLength(fileContent.length);
return new ResponseEntity<>(fileContent, headers, HttpStatus.OK);
Setting Content-Disposition header I was able to download the file with the #ResponseBody annotation on my method.
This is how I do it with Spring Boot and Guava:
#RequestMapping(value = "/getimage", method = RequestMethod.GET, produces = MediaType.IMAGE_JPEG_VALUE)
public void getImage( HttpServletResponse response ) throws IOException
{
ByteStreams.copy( getClass().getResourceAsStream( "/preview-image.jpg" ), response.getOutputStream() );
}
In spring 4 it's very easy you don't need to make any changes in beans. Only mark your return type to #ResponseBody.
Example:-
#RequestMapping(value = "/image/{id}")
public #ResponseBody
byte[] showImage(#PathVariable Integer id) {
byte[] b;
/* Do your logic and return
*/
return b;
}
I think you maybe need a service to store file upload and get that file.
Check more detail from here
1) Create a Storage Sevice
#Service
public class StorageService {
Logger log = LoggerFactory.getLogger(this.getClass().getName());
private final Path rootLocation = Paths.get("upload-dir");
public void store(MultipartFile file) {
try {
Files.copy(file.getInputStream(), this.rootLocation.resolve(file.getOriginalFilename()));
} catch (Exception e) {
throw new RuntimeException("FAIL!");
}
}
public Resource loadFile(String filename) {
try {
Path file = rootLocation.resolve(filename);
Resource resource = new UrlResource(file.toUri());
if (resource.exists() || resource.isReadable()) {
return resource;
} else {
throw new RuntimeException("FAIL!");
}
} catch (MalformedURLException e) {
throw new RuntimeException("FAIL!");
}
}
public void deleteAll() {
FileSystemUtils.deleteRecursively(rootLocation.toFile());
}
public void init() {
try {
Files.createDirectory(rootLocation);
} catch (IOException e) {
throw new RuntimeException("Could not initialize storage!");
}
}
}
2) Create Rest Controller to upload and get file
#Controller
public class UploadController {
#Autowired
StorageService storageService;
List<String> files = new ArrayList<String>();
#PostMapping("/post")
public ResponseEntity<String> handleFileUpload(#RequestParam("file") MultipartFile file) {
String message = "";
try {
storageService.store(file);
files.add(file.getOriginalFilename());
message = "You successfully uploaded " + file.getOriginalFilename() + "!";
return ResponseEntity.status(HttpStatus.OK).body(message);
} catch (Exception e) {
message = "FAIL to upload " + file.getOriginalFilename() + "!";
return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(message);
}
}
#GetMapping("/getallfiles")
public ResponseEntity<List<String>> getListFiles(Model model) {
List<String> fileNames = files
.stream().map(fileName -> MvcUriComponentsBuilder
.fromMethodName(UploadController.class, "getFile", fileName).build().toString())
.collect(Collectors.toList());
return ResponseEntity.ok().body(fileNames);
}
#GetMapping("/files/{filename:.+}")
#ResponseBody
public ResponseEntity<Resource> getFile(#PathVariable String filename) {
Resource file = storageService.loadFile(filename);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"")
.body(file);
}
}
When using produces with MediaType.IMAGE_JPEG_VALUE, make sure that you are returning byte[], but not Byte[]. Very strange, but spring cannot convert it and raises an exception: no converter found.

Integration test with TestRestTemplate for Multipart POST request returns 400

I know that similar question has been here already couple of times but following suggested fixes did not solve my problem.
I have a simple controller with the following endpoint:
#RequestMapping(method = RequestMethod.POST)
public ResponseEntity<String> singleFileUpload(#RequestParam("file") MultipartFile file) {
log.debug("Upload controller - POST: {}", file.getOriginalFilename());
// do something
}
I am trying to write an integration test for it using Spring TestRestTemplate but all of my attemps end with 400 - Bad Request (no logs clarifying what went wrong in console).
The log inside the controller did not get hit so it failed before getting there.
Could you please take a look on my test and suggest what am I doing wrong?
#Test
public void testUpload() {
// simulate multipartfile upload
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("image.jpg").getFile());
MultiValueMap<String, Object> parameters = new LinkedMultiValueMap<String, Object>();
parameters.add("file", file);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<MultiValueMap<String, Object>>(parameters, headers);
ResponseEntity<String> response = testRestTemplate.exchange(UPLOAD, HttpMethod.POST, entity, String.class, "");
// Expect Ok
assertThat(response.getStatusCode(), is(HttpStatus.OK));
}
I tried the following:
#Test
public void testUpload() {
LinkedMultiValueMap<String, Object> parameters = new LinkedMultiValueMap<String, Object>();
parameters.add("file", new org.springframework.core.io.ClassPathResource("image.jpg"));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<LinkedMultiValueMap<String, Object>> entity = new HttpEntity<LinkedMultiValueMap<String, Object>>(parameters, headers);
ResponseEntity<String> response = testRestTemplate.exchange(UPLOAD, HttpMethod.POST, entity, String.class, "");
// Expect Ok
assertThat(response.getStatusCode(), is(HttpStatus.OK));
}
As you can see I used the org.springframework.core.io.ClassPathResource as object for the file and ti worked like a charm
I hope it's useful
Angelo
FileSystemResource also could be used in case if you want to use java.nio.file.Path.
Package: org.springframework.core.io.FileSystemResource
For example, you could do this:
new FileSystemResource(Path.of("src", "test", "resources", "image.jpg"))
Full code example:
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UploadFilesTest {
private final TestRestTemplate template;
#Autowired
public UploadFilesTest(TestRestTemplate template) {
this.template = template;
}
#Test
public void uploadFileTest() {
var multipart = new LinkedMultiValueMap<>();
multipart.add("file", file());
final ResponseEntity<String> post = template.postForEntity("/upload", new HttpEntity<>(multipart, headers()), String.class);
assertEquals(HttpStatus.OK, post.getStatusCode());
}
private HttpHeaders headers() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
return headers;
}
private FileSystemResource file() {
return new FileSystemResource(Path.of("src", "test", "resources", "image.jpg"));
}
}
Rest controller:
#RestController
public class UploadEndpoint {
#PostMapping("/upload")
public void uploadFile(#RequestParam("file") MultipartFile file) {
System.out.println(file.getSize());
}
}

SPRING - REST Template - Upload File using File Input Stream & Other primitve data

I know this has been discussed many times and I have searched a lot on Google / Stackoverflow, but can't seem to get it working.
I have a Spring MVC web application, JSP sends media file along with some text fields, the controller captures the Input Stream and other form data (some text fields), and creates a POJO object of type FileUploadRequest. The complete data (file + text fields) have to be passed as-is to another service (third party service) for upload.
I am using Spring REST Template to connect to the third part service. Below are the code snippets:
RestTemplate Initialization (Java Config)
#Bean
public ClientHttpRequestFactory httpRequestFactory() {
final HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient());
requestFactory.setBufferRequestBody(false);
return requestFactory;
}
#Bean
public RestTemplate getRestTemplate() {
final RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(httpRequestFactory()); // apache http library
restTemplate.setMessageConverters(getMessageConverters());
}
private List<HttpMessageConverter<?>> getMessageConverters() {
final List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
final FormHttpMessageConverter e = new FormHttpMessageConverter();
e.addPartConverter(new MappingJackson2HttpMessageConverter());
converters.add(e);
return converters;
}
#Bean
public CommonsMultipartResolver multipartResolver() {
final CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
return commonsMultipartResolver;
}
Controller Code:
public APPResponse uploadFile(final HttpServletRequest request) {
final FileUploadRequest uploadRequest = new FileUploadRequest();
final List<FileItem> items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);
for (final FileItem item : items) {
if (item.isFormField()) {
String fieldValue = item.getString();
uploadRequest.setEnabled(Boolean.valueOf(fieldValue));
} else {
String fileName = FilenameUtils.getName(item.getName());
InputStream fileContent = item.getInputStream();
uploadRequest.setFileName(fileName);
uploadRequest.setFileStream(fileContent);
}
}
uploadFileToService(uploadRequest);
}
POJO Class:
public class FileUploadRequest {
private String fileName;
private InputStream fileStream;
private boolean enabled;
// getter setters...
}
uploadFileToService method implementation
public FileUploadResponse uploadFileToService(final FileUploadRequest uploadRequest) {
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
final String url = <URL where the file is to passed as is>;
MultiValueMap<String, Object> parameters = new LinkedMultiValueMap<String, Object>();
parameters.set("Content-Type","multipart/form-data");
parameters.add("file", uploadRequest.getFileStream());
parameters.add("someOtherParam", uploadRequest.isEnabled());
final HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<MultiValueMap<String, Object>>(
parameters, headers);
final ResponseEntity<T> exchange = template.exchange(url,
HttpMethod.POST, httpEntity, FileUploadResponse.class);
}
Now, when I run my application, I get the following error:
Caused by: java.lang.UnsupportedOperationException: getBody not supported
at org.springframework.http.client.HttpComponentsStreamingClientHttpRequest.getBodyInternal(HttpComponentsStreamingClientHttpRequest.java:84)
at org.springframework.http.client.AbstractClientHttpRequest.getBody(AbstractClientHttpRequest.java:47)
at org.springframework.http.converter.FormHttpMessageConverter.writeMultipart(FormHttpMessageConverter.java:299)
at org.springframework.http.converter.FormHttpMessageConverter.write(FormHttpMessageConverter.java:238)
at org.springframework.http.converter.FormHttpMessageConverter.write(FormHttpMessageConverter.java:87)
at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:777)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:566)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:529)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:447)
Please let me know what is it that I am missing, I am not able to figure out the issue.
If further details are needed, I can share
Thanks!!
Use MultipartFile from Spring Web, then just use #RequestParam("file") MultipartFile file as an argument in your controller. Then you will have access to the stream along with all other properties that came with the upload.
So, looks like I resolved it. The issue is due to a bug on Spring 4.1.1 Release. It got resolved in 4.2.0
Changed the pom dependency to use 4.2.0 and now it works fine.

Categories