• Fat Cats Boardgame
  • Wicket UI Library
  • About Me

Java and Wicket web development thoughts, tutorials, and tips

roman@coderdreams.com
Coder DreamsCoder Dreams
  • Fat Cats Boardgame
  • Wicket UI Library
  • About Me

Wicket quick tip #2: Print to PDF

April 11, 2020 Posted by Roman Sery wicket No Comments

I’ve decided to start a new series of ‘quick tip’ posts. Each post will be short and focused on a particular problem, an interesting technique, or to improve your productivity.

What we want to do

A common requirement in web apps is the ability to generate a PDF file with dynamic content. There are libraries available that allow you to build the PDF using a low-level approach, step by step. However, a much simpler way that might work for you is to just use regular HTML pages and transform them into PDF. We’ll be using the great iTextPdf library.

How to do it

The first thing we need is the ability to convert Wicket Webpages, Panels, and Components into an HTML string. Fortunately, Wicket makes this very easy for us!

	public static String renderPanelToString(Panel panel) {
		CharSequence cs = ComponentRenderer.renderComponent(panel);
		return cs != null ? cs.toString() : "";
	}

	public static String renderPageToString(PageProvider pp) {
		CharSequence cs = ComponentRenderer.renderPage(pp);
		return cs != null ? cs.toString() : "";
	}

Using these utility methods we can now convert any WebPage or Panel into a string.

Now let’s create a service class that will utilize iTextPdf to convert HTML into PDF:

public class PdfService {

	public void printUrlToPdf(String html, OutputStream output) {
		try {
			String xhtml = convertHtmlToXHTML(html);

			Document document = new Document(PageSize.LETTER.rotate());
			PdfWriter writer = PdfWriter.getInstance(document, output);
			writer.setInitialLeading(12.5f);
			document.open();

			document.newPage();

			Paragraph p1 = new Paragraph();
			ElementList list = XMLWorkerHelper.parseToElementList(xhtml, null);
			p1.addAll(list);
			document.add(p1);

			document.close();
		} catch (Exception e) {

		}
	}

	private String convertHtmlToXHTML(String input) {
		org.jsoup.nodes.Document d = Jsoup.parse(input, "US-ASCII");
		d.outputSettings().syntax(org.jsoup.nodes.Document.OutputSettings.Syntax.xml);
		return d.html();
	}
}

You’ll notice that we first have to convert the HTML into strict XHTML for this to work. This is meant as a simple starting example, but you may need to do further transformations of your HTML in order for it to look good inside of the PDF. You may need to transform some tags such as spans and header tags into divs.

How to use it

Now let’s look at how to actually use our PdfService class. We create a resource stream that will be attached to the current request cycle and when the user navigates to this page, they will be prompted to download the PDF as file named “export.pdf”.

public class PrintPdfTestPage extends WebPage {
    @SpringBean private PdfService pdfService;
    
    public PrintPdfTestPage() throws IOException {
        super();

        try (AbstractResourceStreamWriter resourceStream = new AbstractResourceStreamWriter() {
            @Override
            public void write(OutputStream output) {
                String html = UIHelpers.renderPageToString(new PageProvider(PageSizeTest2.class, new PageParameters()));
                pdfService.printUrlToPdf(html, output);
            }
        }) {
            RequestCycle.get().scheduleRequestHandlerAfterCurrent(
                    new ResourceStreamRequestHandler(resourceStream).setFileName("export.pdf").setContentDisposition(ContentDisposition.ATTACHMENT));
        }
    }
}

You can also generate the PDF in response to a button click using the technique discussed here.

download = new AJAXDownload() {
            @Override
            public void onRequest() {
                try (AbstractResourceStreamWriter resourceStream = new AbstractResourceStreamWriter() {
                    @Override
                    public void write(OutputStream output) {
                        String html = UIHelpers.renderPageToString(new PageProvider(PageSizeTest2.class, new PageParameters()));
                        pdfService.printUrlToPdf(html, output);
                    }
                }) {
                    getComponent().getRequestCycle().scheduleRequestHandlerAfterCurrent(
                            new ResourceStreamRequestHandler(resourceStream).setFileName("export.pdf").setContentDisposition(ContentDisposition.ATTACHMENT));
                } catch (IOException e) {

                }
            }
        };

        testForm.add(new SingleClickAjaxButton("singleClickBtn", testForm, true, null) {
            @Override
            protected void onSubmit(AjaxRequestTarget target) {
                download.initiate(target);
            }
        }.add(download));

Conclusion

I hope this is enough to get you started. There are a lot of other cools things you can do with iTextPdf.

  • Add custom CSS files
  • Add watermark images to each page
  • Create PDF’s from merging several Wicket pages or panels together

You can find the full source on GitHub.

No Comments
Share
1

About Roman Sery

I've been a software developer for over 10 years and still loving Java!

You also might be interested in

Wicket quick tip #1: Async CSV export

Apr 5, 2020

A series of quick tips aimed at improving your productivity.

How to use Wicket component events

How to use Wicket component events

Feb 23, 2020

One of the most powerful features of Wicket, component events, let's you build complex yet decoupled structures.

How to replace PropertyModel with Wicket 8 LambdaModel

Aug 23, 2019

Learn how to replace the loved/hated PropertyModel with the much sexier LambdaModel.

Categories

  • aws
  • customization
  • database
  • debugging
  • enum
  • java
  • models
  • performance
  • projects
  • react
  • software design
  • Spring
  • tool
  • Uncategorized
  • wicket

Recent Posts

  • Rent Day
  • Self-contained Wicket Fragments
  • Pros and cons of unit testing
  • Themeable React Monopoly board
  • Please dont use client-specific release branches

Recent Comments

  • TCI Express Thanks for sharing such insightful information. TCI Express truly stands out as the best air logistics company, offering fast, secure, and efficient air express and cold chain transportation services....

    Tracking down a bug in production Wicket application ·  March 25, 2025

  • Tom Error: A zip file cannot include itself Can you please correct the plugin part so it doesn't use the same folder as input?

    Deploying Spring Boot app to AWS Beanstalk with Nginx customization ·  September 3, 2021

  • Golfman: Reality always wins I've used both Wicket and front-end JS frameworks and, having worked extensively on both, I can tell you that "Speed of development" is definitely NOT with the JS frameworks. You basically end up...

    Five reasons you should use Apache Wicket ·  August 29, 2021

  • Kiriller Sorry can not agree with you, wicket might be a well built technical framework. But the advantages of using a front-end framework like react.js and vue.js can not be beaten by Wicket nowadays. - Speed...

    Five reasons you should use Apache Wicket ·  August 23, 2021

  • Bernd Lauert Sorry but i have to refute your claims with the following arguments: 1. the Wicket community may be small but it is also very responsive, you usually get a helpful answer from the core devs on the...

    Five reasons you should use Apache Wicket ·  July 1, 2021

Archives

  • May 2021
  • October 2020
  • September 2020
  • August 2020
  • July 2020
  • June 2020
  • May 2020
  • April 2020
  • March 2020
  • February 2020
  • January 2020
  • December 2019
  • November 2019
  • October 2019
  • September 2019
  • August 2019
  • July 2019

Contact Me

Send Message
Prev Next