Response returning status but not data - java

I have Jersey endpoint that is attempting to create a CSV file and return it via GET; however, all these attempts end up with the same result - the ok status (200) is returned but no file.
#GET
#Path("/research")
#Produces(MediaType.TEXT_PLAIN)
public Response dumpAllResearchAndSupportData() {
QuickDumpBuilderService dumpBuilderService = getQuickDumpService();
List<DevelopmentProposal> researchOtherProposals = dumpBuilderService.getAllResearchRecords();
String csvLocation = dumpBuilderService.buildCSV(researchOtherProposals);
File file = new File(csvLocation);
String filename = "reserach_" + UUID.randomUUID().toString() + ".csv";
return Response.ok(file, MediaType.TEXT_PLAIN).header("Content-Disposition", "attachment; filename=" + filename).build();
}
My CSV file is properly created, but it fails to be returned along with the response.
Notice above, I'm writing the CSV to a temporary location in my tomcat folder and then passing the path to that file back and then attempting to read that from the location here.
Another attempt with the same result where instead of writing the CSV to temp location, I'm just trying to write the ByteArrayOutputStream to the response object.
#GET
#Path("/research")
#Produces(MediaType.APPLICATION_JSON)
public Response dumpAllResearchAndSupportData() {
QuickDumpBuilderService dumpBuilderService = getQuickDumpService();
// Step 1. Retrieve all research and other proposals
List<DevelopmentProposal> researchOtherProposals = dumpBuilderService.getAllResearchRecords();
// Step 2. Create CSV File
ByteArrayOutputStream csvBaos = dumpBuilderService.buildCSV(researchOtherProposals);
// Step 3. Create spreadsheet
ByteArrayOutputStream excelBaos = dumpBuilderService.createExcelSpreadsheet(csvBaos, servlet);
// Step 4. Return spreadsheet
Response.ResponseBuilder response = Response.ok(excelBaos);
return response.build();
Another attempt where I added this "writer" into the response. This attempt generated an error that a "MessageBodyWriter for the ByteArrayStream was not found." That prompted the attempt below.
#GET
#Path("/research")
#Produces(MediaType.TEXT_PLAIN)
public Response dumpAllResearchAndSupportData() {
....
// Step 4. Return spreadsheet
return Response.ok(getOut(csvBaos.toByteArray())).build();
}
private StreamingOutput getOut(final byte[] csvBytes) {
return new StreamingOutput() {
#Override
public void write(OutputStream out) throws IOException, WebApplicationException {
out.write(csvBytes);
out.flush();
}
};
}
I've looked at the following similar answers, and I've attempted all of them with no success.
Not sure what I'm doing wrong - I suspect that it's something to do with how I setup my endpoint and defer to the Java REST API experts here.
File download/save from a Jersey rest api call using ANGULARJS . file is attached with response as "Content-Disposition"
Download CSV file via Rest
jersey - StreamingOutput as Response entity
Thanks for your help.

Related

Spring RestTemplate upload binary file

Image
I want to write a client code to consume an API. The API is expecting a text file. When I select the binary file option in the postman tool and select any text file from my local it worked. how to implement this in spring ?. I have tried MULTIPART_FORM_DATA but no luck.
If You mean file
#RestController
public class FileContentController {
#RequestMapping(value="/up", method = RequestMethod.POST)
public ResponseEntity<?> upload(#RequestParam("file") MultipartFile file)
throws IOException {
String contentType=file.getContentType());
InputStream i=file.getInputStream();
return new ResponseEntity<>(HttpStatus.OK);
}
return null;
}
also spring boot has multi part confs, you should enable it and set size and tempdir
,In Earlier version spring boot need to add:
spring.servlet.multipart.max-file-size=128KB
spring.servlet.multipart.max-request-size=128KB
spring.servlet.multipart.enabled=true
spring.servlet.multipart.location=${java.io.tmpdir}
However in your client code you should not set content-type application/json in your header post request
simple fetch should be such
const input = document.getElementById('uploadInput');
const data = new FormData();
data.append('file', input.files[0]);
var resp = await fetch('upload/', {
method: 'POST',
body: data
});
if (!resp.ok) {
throw new Error(`HTTP error! status: ${resp.status}`);
}
if (resp.ok) {
await this.images();
}

How multipart form data upload handles large file

I am using quarkus framework for java application.I have created 2 rest apis for consuming file data.
#POST
#Path("file")
#Consumes(MediaType.APPLICATION_OCTET_STREAM)
#Produces(MediaType.APPLICATION_JSON)
public Response uploadFile(byte[] fileData) {
System.out.println("Received file of size = " + fileData.length);
String s = new String(fileData);
return Response.ok().build();
}
#POST
#Path("files")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_JSON)
public void uploadFile(#MultipartForm FormData fileData) throws IOException {
System.out.println("Received file of size = ");
System.out.println(fileData.file.length());
return Response.ok().build();
}
FormData class looks like this
public class FormData {
#FormParam("file")
#PartType(MediaType.APPLICATION_OCTET_STREAM)
public File file;
}
While both of these rest endpoint works fine for small files. But if i upload file as big as 700MB first endpoint fails with OOM issue while file upload with multipart-form succeed. Can someone explain how memory is managed in case of multipart-form upload?
The second API saves the file to a temp file on the file system. (which I believe is being automatically deleted when the call completes and the File is closed)
The first API saves the file to a byte stream (array) in memory - that's why you're getting an OOM error.

Rest template read response as stream and pass to spring controller(Get InputStream with rest Template)

I have a url which download the large size zip file.It returns the response as stream.though file size is large first it returns 200(HTTPSTATUK.OK) and continues download.
I have to implement a new spring controller which call the above url through rest template.I have to read the response returned by rest template and pass to controller.initially I have implemented in below way
#GetMapping("/export/downloadFile")
public ResponseEntity<byte[]> downloadData(Model model,
#ModelAttribute(EXCEPTION_COLLECTOR) ExceptionCollector exceptionCollector,
#RequestParam("userName") String userName,
#RequestParam("startDate") Date startDate,
#RequestParam("endDate") Date endDate,
#RequestParam("reason") String reason) {
URI uri = /building url here/;
return restTemplate.exchange(uri, HttpMethod.GET, new HttpEntity<>(httpHeaders), byte[].class);
}
since I am using ResponseEntity<byte[]> , rest template waits till entire file loaded into memory.so very frequently I am getting socket timeout issue.
Do we have way to read the response as stream and return to controller.
I found few things about restTemplate.execute .
restTemplate.execute(uri,HttpMethod.GET,requestCallBack,clientHttpResponse -> {
File ret = File.createTempFile("download", ".zip",new File("/Users/bokkavijay/Desktop"));
StreamUtils.copy(clientHttpResponse.getBody(), new FileOutputStream(ret));
return ret;
});
above snippet can copy the file to our local with out time out but this is not what I need.
how can we pipe the stream in clientHttpResponse to controller ?
I found the working implementation
Controller
#GetMapping("/readResponseAsStream")
public ResponseEntity<StreamingResponseBody> downloadAsStream(Model model,HttpServletResponse response) {
HttpHeaders httpHeaders=new HttpHeaders();
httpHeaders.add("Transfer-Encoding","chunked");
httpHeaders.add("Content-Type","x-zip-compressed");
httpHeaders.add("Content-Disposition", "attachment;filename=sample.zip");
ServletOutputStream servletOutputStream=response.getOutputStream();
StreamingResponseBody downloadFile = out -> {
RequestCallback requestCallBack=request->{
request.getHeaders().add(//Add headers here);
};
ResponseExtractor<ServletOutputStream> responseExtractor = clientHttpResponse -> {
//code snippet if you want to write response stream to HttpServletResponse
byte[] buff = new byte[800000];
int bytesRead = 0;
while ((bytesRead = clientHttpResponse.getBody().read(buff)) != -1) {
servletOutputStream.write(buff, 0, bytesRead);
}
return servletOutputStream;
//Incase if you want to copy file to you local
File ret = File.createTempFile("download", ".zip",new File("Add Local system directory address here"));
StreamUtils.copy(clientHttpResponse.getBody(), new FileOutputStream(ret));
//You can copy the the clientHttpResponse.getBody() to ByteArrayInputStream and return
// Don't return clientHttpResponse.getBody() directly because rest template will close the inputStream(clientHttpResponse.getBody()) after .execute completed
//if you want to write restTemplate.execute in dao layer , pass servletOutputStream as a argument to method
};
restTemplate.execute(URL_ADDRESS,HttpMethod.GET,requestCallBack,responseExtractor);
};
return new ResponseEntity(downloadFile,httpHeaders,HttpStatus.OK);
}
If you write the response directly to HttpServletResponse , controller download the file when we access in browser

Jersey REST image GET issue

i have a simple question.
Lets say that i want to download multiple specific images when i call my GET method in my REST API from a directory, given that i have their names. eg.
../folder
name1.png
name2.png
name3.png
name4.png
And i want to download name2.png, name3.png.
Everything that i could dig up was regarding only 1 image per call, like this:
#Path("/image")
public class ImageService {
private static final String FILE_PATH = "c:\\picture.png";
#GET
#Path("/get")
#Produces("image/png")
public Response getFile() {
File file = new File(FILE_PATH);
ResponseBuilder response = Response.ok((Object) file);
response.header("Content-Disposition",
"attachment; filename=image_from_server.png");
return response.build();
}
}
The thing that has come to my mind is to send a zip or something like that. Could anyone tell me if this is possible, and if it is how to do it? Thanks.

Returning file from REST from server location

Hi I am returning a file by using the below code in REST Service Class
#Path("/file")
public class FileService {
private static final String FILE_PATH = "c:\\file.log";
#GET
#Path("/get")
#Produces("text/plain")
public Response getFile() {
File file = new File(FILE_PATH);
ResponseBuilder response = Response.ok((Object) file);
response.header("Content-Disposition", "attachment; filename=\"file_from_server.log\"");
return response.build();
}
}
I just want to know How I can pass a file which comes from a HTTP call for e.g
"http://www.analysis.im/uploads/seminar/pdf-sample.pdf".The above code calls from a drive .I want to return files from a server through REST call.
You have to read the file content, set the appropriate media type and return the content as byte array similar to the following:
final byte[] bytes = ...;
final String mimeType = ...;
Response.status(Response.Status.OK).entity(bytes).type(mimeType).build();

Categories

Resources