How to save generated pdf as blob in Java - java

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)

Related

Consume Json with excel file in spring boot rest api

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

How to return an Image to browser in rest API in JAVA from folder?

I have a folder in my NetBeans project with images. I have a H2 database with a "properties" table.
The images are named after a column in the properties table for convenience. This is my code so far.
#PostMapping(value = "/image/large/{id}", produces = MediaType.IMAGE_PNG_VALUE)
public ResponseEntity<Image> getPicture(#PathVariable long id)throws Exception{
System.out.println(id);
//System.out.println(barcode);
Properties prop1 = new Properties();
prop1 = propService.findOne(id);
String filepath = prop1.getPhoto();
String img = "static/images/"+filepath;
return img;
}
How can I implement this in my rest controller? Struggling to find a correct way to implement this, any help appreciated.
From the code you have provided, you can return a string representing an image location or path. This path can then be used in am image <img /> tag.
The second option is to read your file using an inputstream and convert the image to base46 (which you then return to the client).

Transferring and saving MultipartFile instance

I have the following method, with the simple aim to store the contents of a given MultipartFile instance under a specified directory:
private void saveOnDisk(final String clientProductId, final MultipartFile image, final String parentDirectoryPath, final String fileSeparator) throws IOException
{
final File imageFile = new File(parentDirectoryPath + fileSeparator + clientProductId + image.getOriginalFilename());
image.transferTo(imageFile);
OutputStream out = new FileOutputStream(imageFile);
out. //... ? How do we proceed? OutputStream::write() requires a byte array or int as parameter
}
For what it might be worth, the MultipartFile instance is going to contain an image file which I receive on a REST API I'm building.
I've checked some SO posts such as this and this but this problem is not quite touched: I'm effectively looking to create an entirely new image file and store it on a specified location on disk: the method write() of OutputStream, given that it requires byte[] or int params, doesn't seem to be fitting my use case. Any ideas?

Get number of pages of a document

I have just implemented a Java code in order to get number of pages of a document, but it only serves for PDF files. I need to count number of pages of others files (Docx, HTML, etc). Any idea?
My code is:
public int numberOfPages(#RequestBody() MultipartFile inputFile) throws Exception {
int numberOfPages = 0;
InputStream fileName = inputFile.getInputStream();
PDDocument document = PDDocument.load(fileName);
if (document != null) {
numberOfPages = document.getNumberOfPages();
}
return numberOfPages;
}
I think that that is not as easy task as it seems because the page number deppends on the size of the paper, type of the printer, size of the image, etc.
One possible solution can be to convert the input document to PDF and then you can count pages easily. You can store the PDF content as well with the original documents or you can use the toPdf(FileInputStream document) method on the fly each time when you need the page number info. It deppends on the quantity of files and performance requirements.
It can convert html, office documents, pure text and images to PDF.
You can use Apache Tika to check the type of the uploaded file and then based on this info you can execute the proper method to convert uploaded content to PDF.
Check the file type:
public static MediaType getMediaType(final byte[] content) throws IOException {
try (InputStream stream = new ByteArrayInputStream(content)) {
TikaConfig tika = TikaConfig.getDefaultConfig();
Metadata metadata = new Metadata();
return tika.getDetector().detect(stream, metadata);
}
}
Then:
MediaType mediaType = ContentTypeDetector.getMediaType(content);
String uploadedContent = mediaType.toString();
if (uploadedContent.equals("image/jpeg") {
PDF pdf = SomeClass.jpgToPdf(...)
} else if (uploadedContent.equals(...) {
PDF pdf = SomeClass....(...)
}
iText is a nice Java library to create PDF files from the uploaded files based on your settings.

Read PDVInputStream dicomObject information on onCStoreRQ association request

I am trying to read (and then store to 3rd party local db) certain DICOM object tags "during" an incoming association request.
For accepting association requests and storing locally my dicom files i have used a modified version of dcmrcv() tool. More specifically i have overriden onCStoreRQ method like:
#Override
protected void onCStoreRQ(Association association, int pcid, DicomObject dcmReqObj,
PDVInputStream dataStream, String transferSyntaxUID,
DicomObject dcmRspObj)
throws DicomServiceException, IOException {
final String classUID = dcmReqObj.getString(Tag.AffectedSOPClassUID);
final String instanceUID = dcmReqObj.getString(Tag.AffectedSOPInstanceUID);
config = new GlobalConfig();
final File associationDir = config.getAssocDirFile();
final String prefixedFileName = instanceUID;
final String dicomFileBaseName = prefixedFileName + DICOM_FILE_EXTENSION;
File dicomFile = new File(associationDir, dicomFileBaseName);
assert !dicomFile.exists();
final BasicDicomObject fileMetaDcmObj = new BasicDicomObject();
fileMetaDcmObj.initFileMetaInformation(classUID, instanceUID, transferSyntaxUID);
final DicomOutputStream outStream = new DicomOutputStream(new BufferedOutputStream(new FileOutputStream(dicomFile), 600000));
//i would like somewhere here to extract some TAGS from incoming dicom object. By trying to do it using dataStream my dicom files
//are getting corrupted!
//System.out.println("StudyInstanceUID: " + dataStream.readDataset().getString(Tag.StudyInstanceUID));
try {
outStream.writeFileMetaInformation(fileMetaDcmObj);
dataStream.copyTo(outStream);
} finally {
outStream.close();
}
dicomFile.renameTo(new File(associationDir, dicomFileBaseName));
System.out.println("DICOM file name: " + dicomFile.getName());
}
#Override
public void associationAccepted(final AssociationAcceptEvent associationAcceptEvent) {
....
#Override
public void associationClosed(final AssociationCloseEvent associationCloseEvent) {
...
}
I would like somewhere between this code to intercept a method wich will read dataStream and will parse specific tags and store to a local database.
However wherever i try to put a piece of code that tries to manipulate (just read for start) dataStream then my dicom files get corrupted!
PDVInputStream is implementing java.io.InputStream ....
Even if i try to just put a:
System.out.println("StudyInstanceUID: " + dataStream.readDataset().getString(Tag.StudyInstanceUID));
before copying datastream to outStream ... then my dicom files are getting corrupted (1KB of size) ...
How am i supposed to use datastream in a CStoreRQ association request to extract some information?
I hope my question is clear ...
The PDVInputStream is probably a PDUDecoder class. You'll have to reset the position when using the input stream multiple times.
Maybe a better solution would be to store the DICOM object in memory and use that for both purposes. Something akin to:
DicomObject dcmobj = dataStream.readDataset();
String whatYouWant = dcmobj.get( Tag.whatever );
dcmobj.initFileMetaInformation( transferSyntaxUID );
outStream.writeDicomFile( dcmobj );

Categories