Skip to Content
Technical Articles
Author's profile photo Frank Xie

How to transfer file from CAP backside

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.

Assigned Tags

      Be the first to leave a comment
      You must be Logged on to comment or reply to a post.