I am writing a code in Spring Boot where i want to download response as a .json file(Json file) which should not be created in any of my project directory but it should be created on the fly from java Object
#RequestMapping(value = "/", method = RequestMethod.GET,produces = "application/json")
public ResponseEntity<InputStreamResource> downloadPDFFile()
throws IOException {
User user = new User();
user.setName("Nilendu");
user.setDesignation("Software Engineer");
createJsonFile(user);
ClassPathResource jsonFile = new ClassPathResource("a.json");
HttpHeaders headers = new HttpHeaders();
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
headers.add("Pragma", "no-cache");
headers.add("Expires", "0");
return ResponseEntity
.ok()
.contentLength(jsonFile.contentLength())
.contentType(
MediaType.parseMediaType("application/octet-stream"))
.body(new InputStreamResource(jsonFile.getInputStream()));
}
void createJsonFile(User user) {
ObjectMapper mapper = new ObjectMapper();
try {
// Convert object to JSON string and save into a file directly
File file = new File("src/main/resources/a.json");
System.out.println(file.exists()+" ++++");
mapper.writeValue(file, user);
System.out.println("File Created");
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
I am able to do this with above code but every time i make request it creates a new file a.json in src/main/resource directory Which i don't want . i don't want to create this file in any directoy but still i should be able to download the file
Then don't write it to a file!
byte[] buf = mapper.writeValueAsBytes(user);
return ResponseEntity
.ok()
.contentLength(buf.length)
.contentType(
MediaType.parseMediaType("application/octet-stream"))
.body(new InputStreamResource(new ByteArrayInputStream(buf)));
EDIT
To prompt browser for .json file type add a header
.header("Content-Disposition", "attachment; filename=\"any_name.json\"")
you dont need to create a file, just convert the object to json using Gson,
Gson gson = new Gson ();
String jsonString = gson.toJson (user);
Related
I'm using SpringBoot 3.0.1 and I'm trying to get a file stored in the backend using Axios.
The controller is the following:
#GetMapping(value = "/api/files/{fileName}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<?> getFile(final #PathVariable("fileName") String fileName) {
try {
Path filePath = Path.of(fileName);
File file = filePath.toFile();
HttpHeaders responseHeaders = new HttpHeaders();
String filename = filePath.getFileName().toString();
responseHeaders
.setContentDisposition(ContentDisposition.builder("attachment")
.filename(filename, StandardCharsets.UTF_8)
.build());
FileSystemResource fileSystemResource = new FileSystemResource(file);
return ResponseEntity
.ok()
.headers(responseHeaders)
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.contentLength(file.length())
.lastModified(file.lastModified())
.body(fileSystemResource);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
When I get the answer (status is 200), the header I've set in the controller is not given. In particular, the Content-Disposition header is not defined in the answer.
I'm wondering if there is any missing configuration that must be set in Sprint Boot in order to be allowed to set a custom header. Anyone who knows what can cause this and how to fix it?
I could see many related topics, but I have a specific problem. I am using spring boot controller to download a zip file. I am able to download the file when it is http verb get, but as I have to pass a big json payload I changed to post. Since then instead of downloading it as file it is responding the contents of the file with some ascii characters. Below is the method in controller for downloading the file.
#ApiResponses(value = { #ApiResponse(code = 404, message = "file could not be found"),
#ApiResponse(code = 200, message = "File was created sucessfully") })
#PostMapping(path="/download-file/1.0", produces="application/zip")
public ResponseEntity<InputStreamResource> downloadFile(
#ApiParam(value = "File creation contents", required = true) #RequestBody InputDetailsVO inputDetailsVO) {
File file = null;
InputStreamResource resource = null;
HttpHeaders headers = new HttpHeaders();
try {
//Creating InputStreamResource out of zip file
resource = new InputStreamResource(new FileInputStream(file));
String contentType = "application/zip";
if (!StringUtils.isEmpty(contentType)) {
headers.setContentType(MediaType.parseMediaType(contentType));
}
headers.add("Content-Disposition","attachment; filename=\""+file.getName()+"\"");
} catch (Exception e) {
log.error("Issue with file creation",e);
}
return ResponseEntity.ok()
.contentLength(file.length())
.contentType(MediaType
.parseMediaType(MediaType.APPLICATION_OCTET_STREAM_VALUE))
.headers(headers).body(resource);
}
Below is the response I am getting instead of file download
PK;��N <?xml version="1.0" encoding="UTF-8"?>
<employeeDetails>
<name>Harry</name>
<age>30</30>
<email>test#test.com</test>
</employeeDetails>PK�qB�#Y;YPK;��N�qB�#Y;Yemployee details.xmlPKL�Y
Try like this, you can download any type of file. I assume that InputDetailsVO contains the name of the file or you can have your own logic to pick the file name. On the top of this method, you can provide swagger related annotations.
#PostMapping(value = "/download-file/1.0", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<?> downloadFile(#RequestBody InputDetailsVO inputDetailsVO) {
String dirPath = "your-location-path";
byte[] fileBytes = null;
try {
String fileName = inputDetailsVO.getFileName();
fileBytes = Files.readAllBytes(Paths.get(dirPath + fileName));
} catch (IOException e) {
e.printStackTrace();
}
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"")
.body(fileBytes);
}
I also had a similar use case. I am sharing the code which had solved the issue.
#RequestMapping(value="/download",method=RequestMethod.GET,produces="application/zip" )
public ResponseEntity<?> download(HttpServletResponse response) throws IOException
{
//Some Code...
File file = new File("F:\\Folder\\Folder\\Folder\\"+filename);
InputStreamResource resource2 = new InputStreamResource(new FileInputStream(file));
response.setContentType("application/zip");
response.setHeader("Content-Disposition", String.format("inline; filename=\"" + filename + "\""));
response.setHeader("responseType", "arraybuffer");
response.setHeader("Content-Length", ""+file.length());
return new ResponseEntity<InputStreamResource>(resource2,HttpStatus.ACCEPTED);
}
I'm developing a Rest API, will be responsible to return a csv file as response.
This is my Api interface:
#Api(value = Constantes.REPORTS)
public interface ExtractFileApi {
#RequestMapping(value = Constantes.REPORTS_URL, produces = "application/csv", method = RequestMethod.GET)
public ResponseEntity<InputStreamResource> getExtractFile() throws IOException;
}
And this is my interface implementation:
#RestController
public class ExtractFileApiController implements ExtractFileApi {
#Override
public ResponseEntity<InputStreamResource> getExtractFile() throws IOException {
ClassPathResource pdfFile = new ClassPathResource("pdf-sample.csv");
HttpHeaders headers = new HttpHeaders();
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
headers.add("Pragma", "no-cache");
headers.add("Expires", "0");
return ResponseEntity.ok().headers(headers).contentLength(pdfFile.contentLength())
.contentType(MediaType.parseMediaType("application/octet-stream"))
.body(new InputStreamResource(pdfFile.getInputStream()));
}
For now, my API return a link to download the file, but I don't know how to force the response to be exactly a CSV file (file.csv).
Can any one help me ?
You need to change return type to void and then use following code at end
Path path = Paths.get(pdfFile.getPath());
response.setHeader("content-disposition", "attachment; filename="
+ path.getFileName().toString().replace(" ", "_"));
try {
response.setContentType(Files.probeContentType(path));
response.setContentLength((int) Files.size(path));
// Copy bytes from source to destination, closes both streams.
FileCopyUtils.copy(Files.newInputStream(path),
response.getOutputStream());
} catch (IOException e) {
LOGGER.error("fetching file failed", e);
response.setStatus(500);
}
Try changing the production output MIME type to text/csv instead.
I want to upload a file by calling a rest web-service.
This web-service need a MultipartFile.
I read here that I can do this : Multipart File Upload Using Spring Rest Template + Spring Web MVC
So, here is my code :
public Document uploadDocument(MultipartFile file) {
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(backendURL + "documents/upload");
URI uri = builder.build().encode().toUri();
LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("file", file);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<LinkedMultiValueMap<String, Object>> requestEntity =
new HttpEntity<LinkedMultiValueMap<String, Object>>(map, headers);
try {
ResponseEntity<Document> responseEntity = restTemplate.exchange(uri, HttpMethod.POST, requestEntity, Document.class);
} catch (Exception e) {
e.getMessage(); // Crash here
}
return document.getBody();
}
Jackson try to serialize the file in JSON, but it fail with this error :
Could not write content: No serializer found for class java.io.FileDescriptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: org.springframework.web.multipart.support.StandardMultipartFile["inputStream"]->java.io.FileInputStream["fd"])
What can I do to disable the json serialization of the file ?
Thanks to Jekin Kalariya I found a working solution.
I create a temporary file from my MultipartFile and use it to create a FileSystemResource. I send this FileSystemResource instead of the MultipartFile.
Here is the working code :
public DocumentDetailed uploadDocumentInIfs(MultipartFile file, String userProfile) {
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(backendURL + "documents/upload");
builder.queryParam("user", userProfile);
URI uri = builder.build().encode().toUri();
File tempFile = null;
try {
String extension = "." + getFileExtention(file.getOriginalFilename());
tempFile = File.createTempFile("temp", extension);
file.transferTo(tempFile);
} catch (IOException e) {
e.printStackTrace();
}
LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("file", new FileSystemResource(tempFile));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<LinkedMultiValueMap<String, Object>> requestEntity = new HttpEntity<>(map, headers);
Document document = null;
try {
ResponseEntity<Document> responseEntity =
restTemplate.exchange(uri, HttpMethod.POST, requestEntity, Document.class);
document = responseEntity.getBody();
} catch (Exception e) {
e.getMessage();
}
return document;
}
I have write a simple Spring + Angular application just for learn more about it.
I have a spring controller which is mapped to a URL and when an request comes it returns an image.
I have written all the codes and the spring controller returns me the image but when i set it in the HTML it is not displayed correctly
here is my spring controller
#RequestMapping(value = "image/", method = RequestMethod.GET)
public ResponseEntity<byte[]> getChequeImage(HttpSessionsession,#PathVariable("itemId") Integer itemId,
HttpServletResponse response) {
try{
InputStream in = new FileInputStream(new File("path_to_image.jpg"));
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_JPEG);
return new ResponseEntity<byte[]>(IOUtils.toByteArray(in), headers, HttpStatus.OK);
}catch (IOException e){
LOGGER.error(e);
e.getMessage(), response);
return null;
}
}
here is my HTML code
<img src="{{image}}"/>
image is an Angular variable. Angular service is sending the request and binding the data to the image variable
here is the angular code
#scope.image = "data:image/jpg," + data_from_the_api;
You can't use raw image bytes directly on the page, but you can do Base64 encoding, this would be the adaptations
#RequestMapping(value = "image/", method = RequestMethod.GET)
public ResponseEntity<String> getChequeImage(HttpSessionsession,#PathVariable("itemId") Integer itemId,
HttpServletResponse response) {
try{
InputStream in = new FileInputStream(new File("path_to_image.jpg"));
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_JPEG);
byte[] binaryData = IOUtils.toByteArray(in)
byte[] encodeBase64 = Base64.encodeBase64(binaryData);
String base64Encoded = new String(encodeBase64, "UTF-8");
return new ResponseEntity<String>(base64Encoded , headers, HttpStatus.OK);
}catch (IOException e){
LOGGER.error(e);
e.getMessage(), response);
return null;
}
}
and as TechMa9iac said in the comment you should set #scope.image = "data:image/jpg;base64," + data_from_the_api;