Almost every JAVA project need to generate PDF documents for its users, for example:
The JasperReports is one of the best Java libraries for generating PDF documents.
In this article, I will show you how to generate PDF documents using JasperReports, Spring Boot and Jaspersoft Studio.
Let’s suppose we are working on an e-commerce application (e.g. Hybris), and we want to generate the invoice as a PDF for our customers.
This is a simplified version of how we are going to set up the generation of the invoice using JasperReports.
First of all, we need to create the JasperReports template of our invoice PDF document.
1. Download and install the Jaspersoft Studio.
2. Open the Jaspersoft Studio and create a JasperReports template using the toolbox that comes with it.
I have already generate a JasperReports template, you can find it in Github.
The JasperReports template is an XML file with extension .jrxml.
Let’s shed light on some of the JRXML elements :
This code snippet will add an image to the final pdf file, ]]> this parameter will be filled in Java with path to the image.
.getAddress().getStreetName()]]>
This code snippet adds a dynamic attribute to the pdf file, it will be filled in runtime with proper value: $P.getAddress().getStreetName()
This one is similar to the last one, however this time the field value will be retrieved from the i18n resource bundle depending on the chosen languages (fr, en, it…).
1. Create a file property for each language you need.
2. Extract all the static field from your jrxml template and add them (translated) to your files properties.
## i18n.properties (default and fullback) ## jasper.invoice.title.label=Invoice jasper.invoice.address.label=Shipping Address jasper.invoice.entry.product.label=Product Name jasper.invoice.entry.price.label=Unit Price jasper.invoice.entry.quantity.label=Quantity jasper.invoice.entry.total.label=Total jasper.invoice.total.label=Order Total
## i18n_en.properties (for English) ## jasper.invoice.title.label=Invoice jasper.invoice.address.label=Shipping Address jasper.invoice.entry.product.label=Product Name jasper.invoice.entry.price.label=Unit Price jasper.invoice.entry.quantity.label=Quantity jasper.invoice.entry.total.label=Total jasper.invoice.total.label=Order Total
## i18n.properties (for French) ## jasper.invoice.title.label=Facture jasper.invoice.address.label=Adresse de facturation jasper.invoice.entry.product.label=Nom de produit jasper.invoice.entry.price.label=Prix unitaire jasper.invoice.entry.quantity.label=Quantite jasper.invoice.entry.total.label=Total jasper.invoice.total.label=Total de la facture
1. Create a Spring Boot project using Spring Initializr.
2. Add the JasperReports and the Spring Support artifacts to your pom.xml .
net.sf.jasperreports jasperreports 6.6.0
org.springframework spring-support 2.0.8
3. Add the jrxml template, the i18n files properties and images… to the resources folder of your Spring Boot project.
1. Create a Java service InvoiceService , we will use it to generate the PDF invoice.
@Service public class InvoiceService < // OrderModel is a POJO contains all the data about the Invoice // Locale is used to localize the PDF file (French, English. ) public void generateInvoiceFor(OrderModel order, Locale locale) throws IOException < // We will generate the PDF here >>
OrderModel is a POJO object that holds all the data about the invoice, you can find it in Github.
2. Create a PDF File and initiate a FileOutputStream .
@Service public class InvoiceService < Logger log = LogManager.getLogger(InvoiceService.class); public void generateInvoiceFor(OrderModel order, Locale locale) throws IOException < // Create a temporary PDF file File pdfFile = File.createTempFile("my-invoice", ".pdf"); // Initiate a FileOutputStream try(FileOutputStream pos = new FileOutputStream(pdfFile)) < // We will generate PDF here >catch (final Exception e) < log.error(String.format("An error occured during PDF creation: %s", e)); >> >
3. Load the JRXML template.
@Service public class InvoiceService < Logger log = LogManager.getLogger(InvoiceService.class); // Path to the jrxml template private final String invoice_template_path = "/jasper/invoice_template.jrxml"; public void generateInvoiceFor(OrderModel order, Locale locale) throws IOException < File pdfFile = File.createTempFile("my-invoice", ".pdf"); try(FileOutputStream pos = new FileOutputStream(pdfFile)) < // Load the invoice jrxml template. final JasperReport report = loadTemplate(); >catch (final Exception e) < log.error(String.format("An error occured during PDF creation: %s", e)); >> // Load invoice jrxml template private JasperReport loadTemplate() throws JRException < log.info(String.format("Invoice template path : %s", invoice_template_path)); final InputStream reportInputStream = getClass().getResourceAsStream(invoice_template_path); final JasperDesign jasperDesign = JRXmlLoader.load(reportInputStream); return JasperCompileManager.compileReport(jasperDesign); >>
4. Fill the parameters and the DataSource.
@Service public class InvoiceService < Logger log = LogManager.getLogger(InvoiceService.class); private static final String logo_path = "/jasper/images/stackextend-logo.png"; private final String invoice_template_path = "/jasper/invoice_template.jrxml"; public void generateInvoiceFor(OrderModel order, Locale locale) throws IOException < File pdfFile = File.createTempFile("my-invoice", ".pdf"); try(FileOutputStream pos = new FileOutputStream(pdfFile)) < // Load the invoice jrxml template. final JasperReport report = loadTemplate(); // Create parameters map. final Mapparameters = parameters(order, locale); // Create an empty datasource. final JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(Collections.singletonList("Invoice")); > catch (final Exception e) < log.error(String.format("An error occured during PDF creation: %s", e)); >> // Fill template order parametres private Map parameters(OrderModel order, Locale locale) < final Mapparameters = new HashMap<>(); parameters.put("logo", getClass().getResourceAsStream(logo_path)); parameters.put("order", order); parameters.put("REPORT_LOCALE", locale); return parameters; > // . >
5. Generate the PDF using the JasperReportsUtils of the Spring Support.
@Service public class InvoiceService < Logger log = LogManager.getLogger(InvoiceService.class); private static final String logo_path = "/jasper/images/stackextend-logo.png"; private final String invoice_template_path = "/jasper/invoice_template.jrxml"; public void generateInvoiceFor(OrderModel order, Locale locale) throws IOException < File pdfFile = File.createTempFile("my-invoice", ".pdf"); try(FileOutputStream pos = new FileOutputStream(pdfFile)) < // Load the invoice jrxml template. final JasperReport report = loadTemplate(); // Create parameters map. final Mapparameters = parameters(order, locale); // Create an empty datasource. final JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(Collections.singletonList("Invoice")); // Render the PDF file JasperReportsUtils.renderAsPdf(report, parameters, dataSource, pos); > catch (final Exception e) < log.error(String.format("An error occured during PDF creation: %s", e)); >> // . >
6. Call your service InvoiceService.generateInvoiceFor(. ) with the proper values to generate the PDF.
@SpringBootApplication public class GeneratePdfDocumentApplication implements CommandLineRunner < Logger log = LogManager.getLogger(GeneratePdfDocumentApplication.class); @Resource private OrderService orderService; @Resource private InvoiceService invoiceService; @Override public void run(String. args) throws Exception < log.info("Start invoice generation. "); OrderModel order = orderService.getOrderByCode("XYZ123456789"); invoiceService.generateInvoiceFor(order, Locale.FRANCE); log.info("Invoice generated successfully. "); >// . >
7. If everything goes well the invoice as a PDF file will be generated.
Demo of the final version
Find the source code of this example in GitHub.
Article RatingSoftware Craftsmanship, Stackextend author and Full Stack developer with 6+ years of experience in Java/Kotlin, Java EE, Angular and Hybris…
I’m Passionate about Microservice architectures, Hexagonal architecture, Event Driven architecture, Event Sourcing and Domain Driven design (DDD)…
Huge fan of Clean Code school, SOLID, GRASP principles, Design Patterns, TDD and BDD.
This site uses Akismet to reduce spam. Learn how your comment data is processed.
12 Comments Newest Most Voted Inline Feedbacks View all comments 5 years agomost insightful tutorial on this topic! thanks
veeraraghava 4 years agohow to call deafault method our run method in commandline runner interface as rest controller in requestmapping
4 years agothx , just this method doesnt works on my eclipse , final JasperReport report = loadTemplate();
4 years agoComment ajouter le fichier. Jrxml dans sts, mon sts ne lut pas le fichier
4 years ago 4 years agoThe Render pdf (JasperReportsUtils) with Spring framework 5 doesn’t work more. How can I change ?
Avneesh Saini 2 years agoYou are directly use JasperFillManager and JasperExportManager as shared below:
final JasperPrint jasperPrint = JasperFillManager.fillReport(report, parameters, new JREmptyDataSource());
JasperExportManager.exportReportToPdfFile(jasperPrint, pdfFile.getAbsolutePath());
How to load custom font in Jasper ?
4 years agoYou may use iReport or Jasper studio and install the fonts and generate their extensions and use them in your project.
3 years agoI got this error
net.sf.jasperreports.engine.util.JRFontNotFoundException: Font “Arial Rounded MT Bold” is not available to the JVM. See the Javadoc for more details.
at net.sf.jasperreports.engine.fonts.FontUtil.checkAwtFont(FontUtil.java:604) ~[jasperreports-6.6.0.jar:6.6.0]
at net.sf.jasperreports.engine.fill.SimpleTextLineWrapper.loadFont(SimpleTextLineWrapper.java:384) ~[jasperreports-6.6.0.jar:6.6.0]
at net.sf.jasperreports.engine.fill.SimpleTextLineWrapper.getGeneralFontInfo(SimpleTextLineWrapper.java:354) ~[jasperreports-6.6.0.jar:6.6.0]
at net.sf.jasperreports.engine.fill.SimpleTextLineWrapper.createFontInfo(SimpleTextLineWrapper.java:294) ~[jasperreports-6.6.0.jar:6.6.0]
at net.sf.jasperreports.engine.fill.SimpleTextLineWrapper.start(SimpleTextLineWrapper.java:256) ~[jasperreports-6.6.0.jar:6.6.0]
at net.sf.jasperreports.engine.fill.TextMeasurer.measure(TextMeasurer.java:543) ~[jasperreports-6.6.0.jar:6.6.0]
at net.sf.jasperreports.engine.fill.JRFillTextElement.chopTextElement(JRFillTextElement.java:665) ~[jasperreports-6.6.0.jar:6.6.0]
at net.sf.jasperreports.engine.fill.JRFillTextField.prepare(JRFillTextField.java:784) ~[jasperreports-6.6.0.jar:6.6.0]
at net.sf.jasperreports.engine.fill.JRFillElementContainer.prepareElements(JRFillElementContainer.java:542) ~[jasperreports-6.6.0.jar:6.6.0]
at net.sf.jasperreports.engine.fill.JRFillFrame.prepare(JRFillFrame.java:241) ~[jasperreports-6.6.0.jar:6.6.0]
at net.sf.jasperreports.engine.fill.JRFillElementContainer.prepareElements(JRFillElementContainer.java:542) ~[jasperreports-6.6.0.jar:6.6.0]
at net.sf.jasperreports.engine.fill.JRFillBand.fill(JRFillBand.java:453) ~[jasperreports-6.6.0.jar:6.6.0]
at net.sf.jasperreports.engine.fill.JRFillBand.fill(JRFillBand.java:428) ~[jasperreports-6.6.0.jar:6.6.0]
at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillBandNoOverflow(JRVerticalFiller.java:448) ~[jasperreports-6.6.0.jar:6.6.0]
at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillColumnHeader(JRVerticalFiller.java:496) ~[jasperreports-6.6.0.jar:6.6.0]
at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillReportStart(JRVerticalFiller.java:260) ~[jasperreports-6.6.0.jar:6.6.0]
at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillReport(JRVerticalFiller.java:110) ~[jasperreports-6.6.0.jar:6.6.0]
at net.sf.jasperreports.engine.fill.JRBaseFiller.fill(JRBaseFiller.java:615) ~[jasperreports-6.6.0.jar:6.6.0]
at net.sf.jasperreports.engine.fill.BaseReportFiller.fill(BaseReportFiller.java:432) ~[jasperreports-6.6.0.jar:6.6.0]
at net.sf.jasperreports.engine.fill.JRFillSubreport.fillSubreport(JRFillSubreport.java:818) ~[jasperreports-6.6.0.jar:6.6.0]
at net.sf.jasperreports.engine.fill.JRSubreportRunnable.run(JRSubreportRunnable.java:61) ~[jasperreports-6.6.0.jar:6.6.0]
at net.sf.jasperreports.engine.fill.AbstractThreadSubreportRunner.run(AbstractThreadSubreportRunner.java:221) ~[jasperreports-6.6.0.jar:6.6.0]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_191]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_191]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_191]