Is it possible with spring boot and for example apache poi to get POST request json format with excel file inside?
for example :
POST api/testrequest/
Content-Type: application/json //(maybe another type?)
{
"searchKey": "test1",
"searchValue": file.excel
}
And fetch it to Object?
Now I did something like this :
Controller method :
#PostMapping(
value = "excelentity",
consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE})
public String getExcelAndParseItToEntity(#RequestBody ExcelTemplate file) {
String fileName = file.getFile().getOriginalFilename();
log.info(fileName);
return "test case";
}
And Java Object :
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#ToString
public class ExcelTemplate {
private MultipartFile file;
private String name;
}
But it doesn't work
You can't include it directly but you can encode it as string.
The client sending that json request to your spring boot application can encode the file to base64 and include the resulting string in the json as text.
Something like that:
byte[] fileContent = readExcelFile(file); // Use InputStreams to read all bytes of the excel
String encodedFile = Base64.getEncoder().encodeToString(fileContent);
doRequest(encodedFile); // Do request, set 'encodedFile' as value of 'searchValue' in json
Your json would then look something like that:
{
"searchKey": "test1",
"searchValue": "SGVsbG8gU3RhY2tPdmVyZmxvdyE=..."
}
In your spring boot application simply decode it to bytes again and save it as file or use it directly with a ByteArrayInputStream.
var searchValue = getFromJson(json); // get the value from your json / dto
byte[] decodedBytes = Base64.getDecoder().decode(searchValue);
// Save to a file then use it
saveToFile(decodedBytes);
// Or
// Use it directly as InputStream without saving it to file
var inputStream = new ByteArrayInputStream(decodedBytes);
See this baeldung tutorial for more information on how to use Base64: https://www.baeldung.com/java-base64-encode-and-decode
And this one for the ByteArrayInputStream: https://www.baeldung.com/convert-byte-array-to-input-stream
Related
I have a BDD automation framework setup with Selenium WebDriver and Cucumber with Java. I have configured Rest Assured and I am currently using one JSON payload which is stored in an external JSON file. I am directly reading this JSON file into byte array and then converting the same to String and sending the payload to a post request.
Till now, everything was static and hence, this was working without any issue. However, now the requirement is to send a couple of attributes with dynamic values everytime I make a post call. I know how to send a complete dynamic payload using POJOs but I am looking for a different solution where I can read the payload from the same JSON file and can send dynamic values for few required attributes. Please let me know if this is possible.
Attaching the code for reference.
File which reads the JSON file and sends the payload to post request
public class AddOrderAPIActions {
ConfigReader configReader = new ConfigReader();
Properties prop;
public AddOrderAPIActions() {
prop = configReader.init_prop();
}
//Setting up the API URI
public void setURI() {
String URI = prop.getProperty("apiURI");
RestAssured.baseURI = URI;
}
//Sending the request payload via POST method
public String sendRequestPayload() throws IOException {
//read data from local JSON file then store in byte array
byte[] b = Files.readAllBytes(Paths.get("./src/test/resources/data/addOrder.json"));
//convert byte array to string
String bdy = new String(b);
//input details with header and body
Response response = given().header("Content-type", "application/json").queryParam("api_key", prop.getProperty("apiKey")).body(bdy)
//adding post method
.when().post().then().log().all().extract().response();
JsonPath jp = response.jsonPath();
String shipmentNumber = jp.get("data.shipmentDetails[0].shipmentNumber");
System.out.println("Shipment Number is "+ shipmentNumber);
return shipmentNumber;
}
}
The JSON file with payload
[
{
"originDetails": {
"originCode": "Dynamic_Value",
"originStartTime": "",
"originEndTime": "",
"senderName": "Origin Name",
"senderContactNumber": "9999999999",
"senderAddress": "Bali, Indonesia",
"senderPincode": "201001",
"senderCity": "Delhi",
"senderCountry": "India"
},
]
Here, I want to send a dynamic value for "originCode" attribute and rest of the attributes should be sent as read from the JSON file.
Thanks in advance.
In my Spring Boot app, I am generating pdf file from html string and save it a temp location by using the following approach:
#Override
public PdfResponse downloadPdfFromUrl(final PdfRequest request, final String html) {
// some codes omitted for brevity
Pdf pdf = new Pdf();
String filePath = request.getDownloadPath()+ "/" + request.getItemUuid()+ ".pdf";
pdf.saveAs(filePath);
PdfResponse response = new PdfResponse();
response.setFileDownloadPath(filePath);
response.setFileName(request.getItemUuid());
return response;
}
#Data
public class PdfResponse {
private UUID fileName;
private String fileDownloadPath;
private Long size;
}
At this point, I want to save the generated pdf as blob and return it in a proper format.
1. The client will receive the blob file and then open it as pdf. In this case I think I should create and save blob file from pdf after generating it? Is that right?
2. How could I generate blob from pdf?
3. Which type should I return the generated blob file? Is MultipartFile is a proper format? And I think I cannot return blob directly and have to save it first?
The type matching databases blob storages in java are simply bytes array.
From your filepath, you have to get your pdf binaries from filepath and then send it to your persistance storage like you want :
String filePath = request.getDownloadPath()+ "/" + request.getItemUuid()+ ".pdf";
pdf.saveAs(filePath);
byte[] pdfData = Files.readAllBytes(Paths.get(filePath));
And your pdfResponse should look like this :
#Data
public class PdfResponse {
private UUID fileId;
private String fileName;
private byte[] pdfData;
private Long size;
}
Last but not least I think you will want to be able to download that PDF file from a Spring controller.
Then you can achieve it this way (It's same logic for a PDF or an image) : https://www.baeldung.com/spring-controller-return-image-file
(Just replace .jpg with .pdf)
When we get input from any other Service/API in our own microservice, how our spring-boot application will know that the input type is either XML type or JSON type payload internally. And. After it is getting the actual kind of payload as input if I want to convert from XML to JSON or vice-versa, how it will work, will it have the same native method as below;
public static String xml= "<?xml version=\"1.0\" ?><root><test attribute=\"text1\">XML DATA</test><test attribute=\"text2\">DATA DATA</test></root>";
JSONObject json = XML.toJSONObject(xml);
String jsonString = json.toString(4);
System.out.println(jsonString);
//Convert from XML to JSON
and while converting from XML to JSON,
JSONObject jsonObject = new JSONObject(jsonString);
String xml = "<?xml version=\"1.0\" encoding=\"ISO-8859-15\"?>\n<"+root+">" + XML.toString(jsonObject) + "</"+root+">";
Or is there any other way to convert?
Simply my query is like, how to know what is the input type and how our application will recognize this?
You can read the content type request header as an argument in your controller's class mapping method:
public class APIController {
#GetMapping(
public String getMethod(#RequestBody String body, #RequestHeader("Content-type") String contentType) {
}
}
I am trying to save a PDF using Angular and Spring Boot.
When I make an API call, my Java code is fetching the data from the database and transforming it to a byte-stream. This stream is sent as response.
if(format.equals(Constant.PDF_FORMAT)) {
ByteArrayInputStream stream = reportPDF.generateReportDocument(dtos);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "inline; filename=report.pdf");
return ResponseEntity.ok()
.headers(headers)
.contentType(MediaType.APPLICATION_PDF)
.body(new InputStreamResource(stream));
}
I have to use this response and save the data into a PDF.
Component.ts
public getReports(type?: string): void {
this.params['expected-format'] = type;
if (type === 'json') {
this.Service.getPilotReports(this.params).subscribe((res) => {
this.reportsData = res;
this.pilotBankSpinnerService.closeSpinner();
});
} else {
this.Service.customGetForDownload(this.params).subscribe(
(data: Blob) => {
var file = new Blob([data], { type: 'application/pdf' });
var fileURL = URL.createObjectURL(file);
window.open(fileURL);
var a = document.createElement('a');
a.href = fileURL;
a.target = '_blank';
a.download = 'reports.pdf';
document.body.appendChild(a);
a.click();
},
(error) => {
console.log('getPDF error: ', error);
}
);
}
}
Service.ts
public customGetForDownload<blob, T>(url: string, params: any): any {
const headers = new HttpHeaders({ 'Content-Type': 'application/json', responseType: 'blob' });
const httpParams = this.http.constructParams(params);
const absoluteUrl = this.getAbsoluteUrl(url);
return this.httpClient.get(absoluteUrl, {
headers: headers,
params: httpParams,
responseType: 'blob' as 'json',
observe: 'response',
});
}
Though the file is getting saved. When I try to open the file, it says "Failed to load pdf document".
Syntax Issues
First I see a syntax error:
missing argument in method-call: ByteArrayInputStream stream = reportPDF.generateReportDocument(dtos, ); (after the comma)
With this syntax error you most likely receive a compilation-error on console.
Assume this is a lapse and you can fix it to something like ByteArrayInputStream stream = reportPDF.generateReportDocument(dtos); then it should compile.
Boots without errors? Then test the endpoint!
Assume further your server application boots and runs without errors, then you could test the HTTP-endpoint with a HTTP-call.
You can test using a HTTP-client like CURL, postman or maybe even a browser.
Then you should receive a response with HTTP status code 200 and the body containing the PDF-file as binary with MIME-type application/pdf and specified header Content-Dispositon.
The browser is expected to prompt you with a download-dialogue.
Responding with a binary in Spring
Your InputStreamResource is a valid way, but you should be confident when using it.
In a Spring controller method, you can return the binary data in different types:
ResponseEntity<byte[]> as byte-array
ResponseEntity<ByteArrayOutputStream> as stream (not input-stream for reading input)
ResponseEntity<Resource> as abstract binary content, see Spring's Resource
ResponseEntity<File> as entire file
See also
Spring boot Angular2 file download not working
PDF Blob is not showing content, Angular 2
Return generated pdf using spring MVC
There are also some response-directed ways especially in Spring:
return a InputStreamResource as you did
return a StreamingResponseBody is very convenient
write to a HttpServletResponse, probably the oldest way
See: How To Download A File Directly From URL In Spring Boot
From input to output
Remember: Input is for reading (e.g. from a request), output is for writing (e.g. to a response). So you need an output type, like byte[] or ByteArrayOutputStream etc for your response-body.
When reading input into ByteArrayInputStream stream you could copy from that input to an output-stream with e.g. Apache-Commons IOUtils: IOUtils.copy(in, out);.
Or simply return the byte-array: byte[] data = stream.readAllBytes();
See: Java InputStream to Byte Array and ByteBuffer | Baeldung
I am working on a project where i have to convert XML file in the server and then send them into a JSON form in the client side
The problem is when I have a large XML document since parsing will surpass the limit size of the string.
I even tried changing string into Byte[] but the problem my angular client side accept only JSON form
#RequestMapping(value = "/{var1}/{var2}", method = RequestMethod.GET)
public ResponseEntity<byte[]> getGraph(#PathVariable("var1") String var1, #PathVariable("var2") String var2) {
byte[] result = loadUnloadWorkflow.loadWorkflow("AMAZONTEST", "FR");
return new ResponseEntity<byte[]>(result, HttpStatus.OK);
}
is there a way to parse any XML file whatever it's size into string ?
You could try to convert the XML to an object and then, convert the object to json. What about that?