Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
frank_xie
Product and Topic Expert
Product and Topic Expert
885

Introduction:
In this blog post, we will discuss the process of receiving a PDF file from the frontend, saving its content in a database, and transferring the file to an external service for parsing. We will explore the necessary steps and provide code examples to illustrate the implementation.


Step 1: Saving File Content in the Database

To handle the first step, we can utilize the CAP framework. Follow the link to define the file content and media type in the database. The following code snippet demonstrates the necessary annotations and definitions:



        @Core.MediaType   : filemimetype
uploadfilecontentbinary : LargeBinary;
@Core.IsMediaType : true
filemimetype : String(127);

In the frontend, use a file uploader controller to upload the PDF file. On the backend, no specific operations are required to handle the file upload as the file content will be automatically persisted in the database.



var sPath = oEvent.getSource().getContexts()[0].sPath;
sPath = oEvent.getSource().getContexts()[0].sPath;

var sFileUploadURL = sServicePath + sPath + "/uploadfilecontentbinary";

var oFileUploader = that.getObjectById("uploadReportRawDataDialog", "fileUploaderRawData");

var headerParameterContentType = new sap.ui.unified.FileUploaderParameter();
headerParameterContentType.setName('Content-Type');
headerParameterContentType.setValue('application/pdf');
oFileUploader.addHeaderParameter(headerParameterContentType);

var csrfToken = oFileUploader.getModel().getHttpHeaders()["X-CSRF-Token"];
var headerParameterCSRFToken = new sap.ui.unified.FileUploaderParameter();
headerParameterCSRFToken.setName('x-csrf-token');
headerParameterCSRFToken.setValue(csrfToken);
oFileUploader.addHeaderParameter(headerParameterCSRFToken);

oFileUploader.setUploadUrl(sFileUploadURL);
oFileUploader.upload();

Step 2: Custom Development for Parsing the PDF

To handle the second step, we need to perform some custom development. Refer to the link for more details.


First, define an event handler to process the file content before it is persisted in the database. This can be done using the `@Before` annotation in the CdsService class:



@Before(event = CdsService.EVENT_UPDATE)
public void preProcessCoverImage(CdsUpdateEventContext context, List<Books> books) {
books.forEach(book -> {
book.setCoverImage(new CoverImagePreProcessor(book.getCoverImage()));
});
}

Next, implement the `CoverImagePreProcessor` class, which acts as a proxy to wrap the original `InputStream`:



public class CoverImagePreProcessor extends FilterInputStream {

public CoverImagePreProcessor(InputStream wrapped) {
super(wrapped);
}

@Override
public int read() throws IOException {
int nextByte = super.read();

// ... your custom processing code on nextByte

return nextByte
}

@Override
public int read(byte[] bts, int off, int len) throws IOException {
int bytesRead = super.read(bts, off, len);
int bytesRead = super.read(bts, off, len);
if(HandleTempFile.tempFile == null){
HandleTempFile.tempFile = File.createTempFile("test", ".pdf");
HandleTempFile.out = new FileOutputStream(HandleTempFile.tempFile);
}
if(bytesRead != -1){
HandleTempFile.out.write(bts, off, bytesRead);
}else{
HandleTempFile.out.close();
HandleTempFile.postPDF();
}
return bytesRead;
}
}

The `CoverImagePreProcessor` class saves the file content `InputStream` as a temporary file. Then, it uses `RestTemplate` to upload the temporary file to the external service for parsing.


And when debugging the method in the CoverImagePreProcessor class, you will notice that the read method is called multiple times until the variable bytesRead equals -1. This behavior is in accordance with the principle of InputStream. In order to handle this situation, it is necessary to introduce a separate variable to write the byte arrays into a temporary file.


To facilitate this process, we can create a `HandleTempFile` class:
public class HandleTempFile {
public static File tempFile;
public static FileOutputStream out;
public static String cuurent_id;

public static void postPDF() {

MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
FileSystemResource fileSystemResource = new FileSystemResource(tempFile);

body.add("file", fileSystemResource);

// Add file in ByteArray to body
body.add("options", opitons);

// Set the headers
HttpHeaders headersMap = new HttpHeaders();

headersMap.setContentType(MediaType.MULTIPART_FORM_DATA);
headersMap.set("authorization", "Bearer " + token);
// Add body and headers to HttpEntity
HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(body, headersMap);

// Post the request
//https://blog.csdn.net/loveLifeLoveCoding/article/details/128317783
ResponseEntity<String> response = new RestTemplate().postForEntity(uri, entity, String.class);

//Remove tempFile
tempFile.delete();
tempFile = null;
}
}

The `HandleTempFile` class handles the uploading of the temporary file to the external service using `RestTemplate`. It sets the necessary headers and constructs the `HttpEntity` with the file and other options. Finally, it sends the POST request and cleans up the temporary file.


 

Conclusion:
By following the steps outlined in this blog post, you can successfully handle the upload and parsing of PDF files in the backend. Utilizing the CAP framework and custom development, you can efficiently save the file content in a database and transfer the file to an external service for further processing.