I have a java/spring boot application where I want to build an API endpoint that creates and returns a downloadable excel file. Here is my controller endpoint:
@
Basically , there are few points that you first need to understand & then decide what you want to do ,
1.Is excel creation on disk needed or can you stream it from memory?
If its a download pop up, user might keep it open for long time & memory be occupied during that period ( disadvantage of in memory approach ) .
Secondly, if generated file has to be new for each request ( i.e. data to be exported is different ) then there is no point in keeping it at disk ( disadvantage of in disk approach ) .
Thirdly, it will be hard for an API code to do disk clean up because you never know in advance as when user will finish up his down load ( disadvantage of in disk approach ) .
Answer by Fizik26 is this In - Memory approach where you don't create a file on disk. . Only thing from that answer is that you need to keep track of length of array out.toByteArray()
& that can easily be done via a wrapper class.
2.While downloading a file , your code needs to stream a file chunk by chunk - thats what Java streams are for. Code like below does that.
return ResponseEntity.ok().contentLength(inputStreamWrapper.getByteCount())
.contentType(MediaType.parseMediaType("application/vnd.ms-excel"))
.cacheControl(CacheControl.noCache())
.header("Content-Disposition", "attachment; filename=" + "SYSTEM_GENERATED_FILE_NM")
.body(new InputStreamResource(inputStreamWrapper.getByteArrayInputStream()));
and inputStreamWrapper
is like ,
public class ByteArrayInputStreamWrapper {
private ByteArrayInputStream byteArrayInputStream;
private int byteCount;
public ByteArrayInputStream getByteArrayInputStream() {
return byteArrayInputStream;
}
public void setByteArrayInputStream(ByteArrayInputStream byteArrayInputStream) {
this.byteArrayInputStream = byteArrayInputStream;
}
public int getByteCount() {
return byteCount;
}
public void setByteCount(int byteCount) {
this.byteCount = byteCount;
}
}
Regarding file name, if file name is not an input to end point - that means ..its system generated ( a combination of constant string plus a variable part per user ). I am not sure why you need to get that from resource.
You won't need this wrapper if use - org.springframework.core.io.ByteArrayResource