Hi all, what happens is that I have a servlet, what it does is to generate a PDF using html and css, then that pdf is sent to the frontend to download it.
But what I need to do now is to send information from the java sling model of the template to the servlet, to generate a PDF with the information that is inside the template.
How can I do that, the only solutions that I have found are only for the servlet that are sent to call from the java sling model, but my servlet is sent to call from the frontend, this is the code that I use:
Frontend Call:
package com.project.core.servlets;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.itextpdf.html2pdf.HtmlConverter;
@WebServlet("/PDFServlet")
public class PDFServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// HTML content to be converted to PDF
String htmlContent = "<html><head><style>.my-class { color: red; }</style></head><body><div class=\"my-class\">Hello, World!</div></body></html>";
// Generate PDF from HTML content
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
HtmlConverter.convertToPdf(htmlContent, outputStream);
// Set content type and headers
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=\"output.pdf\"");
// Write PDF to response output stream
response.getOutputStream().write(outputStream.toByteArray());
} catch (IOException e) {
e.printStackTrace();
response.getWriter().println("Error generating PDF: " + e.getMessage());
}
}
}
Topics help categorize Community content and increase your ability to discover relevant content.
Views
Replies
Total Likes
Hi,
I'm sorry, but I don't understand your question correctly. Here are some general guidelines you should keep in mind:
You should extract your PDF logic into an OSGi service so you can use your methods either in the Sling Model or the servlet.
The data which is available in the Sling Model can be retrieved in the Sling servlet as long as you know the path of the resource.
With the above clarification, you should not have a scenario where you really would need to pass data from a Sling Model to a servlet.
Hope this helps
Ok, I will summarize the problem, we have the following files:
1) PDFServlet.java: a servlet that generates a pdf and then sends it to the frontend to download the generated pdf, the information that the PDF have are hardcoded values.
2) Frontend-functions.js: A javascript file that is used in the frontend of a template (page) that what it does is to call the pdf servlet when a button of the page is clicked, to download the pdf that was generated in the same servlet.
3) productModel.java: A java sling model with getters and its respective information.
The way it works now is only with point 1 and point 2, that is to say, the frontend calls the servlet and the servlet delivers something to the frontend.
Now what I want to do is to use point 1, point 2 and point 3 together, the pdf that the servlet generates I want to have and use the information of the java sling model values (example title, description, images, etc) instead of the hardcoded values that are on the PDFServlet
Ok, got it.
So, you have two options here:
//HTL
<sly data-sly-use.model="com.your.Model"></sly>
<div id="myDiv" data-title=${model.title @ context='html'} data-title=${model.desc @ context='html'} >
//JS
var allData = $('#div').data();
$("#download-pdf").on("click", function () {
fetch('/bin/pdfgenerator', {
method: 'GET',
data: allData
headers: {
'Content-Type': 'application/pdf'
}
})
Hope this helps.
I had some doubts when I started to do it with solution 1.
I don't get the values in the servlet even if I call the java sling model, in this case there are 2 java files, one is the interface (ProductDetail.java) and the values (ProductDetailJava.impl).
But if I try to call it to the servlet it simply does not detect the values of the model:
Example
ProductDetail pdpInfo = request.getResource().adaptTo(ProductDetail.class);
String name = “”;
try {
name = pdpInfo.getProductServingSuggestion();
} catch (Exception e) {
name = “ERROR”;
}
Or also
ProductDetailImpl pdpInfo = request.getResource().adaptTo(ProductDetailImpl.class);
String name = “”;
try {
name = pdpInfo.getProductServingSuggestion();
} catch (Exception e) {
name = “ERROR”;
}
My other doubt is that, as the template (page) is composed of several htl joined together, is it possible to use the mentioned logia to send to call the model in the servlet?
Many of the htl use the same template, but they are different htl and css layouts.
Hey, I think you're a bit confused. Let me expand on approach 1 with an example:
The Sling model has the values because it reads the properties from a resource, i.e., /content/myresource.
The servlet won't have access to the resource, but you can explicitly look for that resource, like this:
String path = "/content/myResource" //this can be passed as queryParameter from the JS call
Resource resource = request.getResourceResolver().resolve(path);
3.With the resource, you can adapt to the model. This will automatically invoke your model and populate it with the information from the resource
MyModel model = resource.adaptTo(MyModel.class);
//Now you can use the data will be filled into your model
// So you could utilize the methods from the model, for example:
String title = model.getTitle();
String desc = model.getDesc();
Hope this helps.
How can I get the path to the component resource? Do you have an example of what a url would look like?
I searched the internet for the following solution and send it by parameters in the frontend fetch:
var pathModel = document.location.pathname + “.infinity.json”;
And doing that gives me for example the value:
/content/foods/us/en/test-folder/test-product.html.infinity.json
And then I add the code that you gave me before in the java servlet
String example= “”;
try {
String pathModel = request.getParameter(“pathModel”);
Resource resource = request.getResourceResolver().resolve(pathModel);
ProductDetailImpl productPDP = resource.adaptTo(ProductDetailImpl.class);
example = productPDP.getTitle();
} catch (Exception e) {
example = “ERROR”;
}
But still not working, even if I do it with the ProductDetail.java and ProductDetailImpl.java
you need to do some string manipulation to make "/content/foods/us/en/test-folder/test-product.html.infinity.json" to "/content/foods/us/en/test-folder/test-product"
as there is no content path available with .html extension so you might be getting nullpointer exception.
Hope this helps
Umesh Thakur
Hello, I tried to do the recommendation you give me but still dont work, this is the call to the servlet code (javascript):
And the servlet is modified now with this:
Sorry I make some miss typed wrong the value PathModel and I write sometime PathModelo, but even If I correct that part still not working
@Aaron_Dempwolff you are confusing the Resource Path with the URL path. The model adaptation will work only if you adapt a Resource (node) that meets the conditions of your Sling Model. If you are doing something like window.location you will get the URL path instead.
For example, if you need to use the TeaserModel from wknd page:
URL Path: /content/wknd/us/en/adventures
Resource Path: /content/wknd/us/en/adventures/jcr:content/root/container/teaser
So, you would need to use the ResourcePath to use the adaptTo method.
In HTL, I think you could use ${resource.path @ context='uri'} to get the resource path.
Hope this helps.
Hello, analyzing the solution that you provided, two doubts came to my mind.
1) Once I enter the resource path I could obtain information from the java sling model, but I think, to obtain the information I couldn't use the getter methods of the model, I have to obtain the information in some other way or method?
2) Something that I realized, is that my template (page) is composed of several components at the same time (8 components) to build the page, and when I examine the properties in the crx I see that several values that shows the page of the different components are missing, what can I do in that case to obtain the information of each one of those components (example texts, images, titles, etc) from the page (template)?
For example in the java sling model I have the value Allergens that is one of the components that make the page but is not in the CRX of the page but is showing the value in the page
I discover something debugging, I found that the methods (getters) are getting called but no one of these have values, is this related with that the pages are dynamic?
Because the info of the java sling model is mapped in the page (template)
from Javascript or jquery--->AEM Servlet-->Slingmodel. this will be the call hierarchy.
you will create an object of sling model in the servlet then will get the data from sling model see the point 3 in below blogpost https://aemhelper.blogspot.com/2021/08/common-myths-around-sling-model.html to have a sling model object in servlet, servlet will generate the PDF with the data then will respond to the fron-end call with generated PDF.
Hope this helps
Umesh Thakur
@Aaron_Dempwolff Did you find the suggestions from users helpful? Please let us know if you require more information. Otherwise, please mark the answer as correct for posterity. If you have found out solution yourself, please share it with the community.
Views
Replies
Total Likes