DZone
Java Zone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
  • Refcardz
  • Trend Reports
  • Webinars
  • Zones
  • |
    • Agile
    • AI
    • Big Data
    • Cloud
    • Database
    • DevOps
    • Integration
    • IoT
    • Java
    • Microservices
    • Open Source
    • Performance
    • Security
    • Web Dev
DZone > Java Zone > Static Website Generation With Java and Maven (JBake)

Static Website Generation With Java and Maven (JBake)

Build your static website or blog with JBake ("mvn generate-resources"). Use layouts, macros, and data files.

Geoffrey De Smet user avatar by
Geoffrey De Smet
·
Jul. 10, 21 · Java Zone · Tutorial
Like (4)
Save
Tweet
6.05K Views

Join the DZone community and get the full member experience.

Join For Free

Last week, we migrated the entire www.optaplanner.org website (1399 files) to build with Java and Maven, instead of Ruby and Rake. On the face of it, nothing changed. But in the sources, for our team of Java developers, it is a game-changer.

Our java team can now contribute to the website easily. Within hours of completing the migration, there was already a commit of one of our developers who would rather not touch the previous source code with a ten-foot pole.

We built this site.
We built this site on Java and Maven.
We built this site.
We built this site on JBake and Freemarker.

Why a Static Website Generator?

A static website generator transforms templates and content files into a static HTML/JS/CSS website. This has many advantages over a Content Management System (CMS) for projects such as ours:

  • Hosting is cheap. GitHub pages even host static websites for free.

  • The source files go into Git for backup and history.

  • The source files are in plain text:

    • Changes come in as a Pull Request for proper review and CI validation.

    • The sources are open in our IDEs, which encourages refactoring them alongside the code. This results in less stale content.

For many years, Awestruct has served us well. But due to lack of activity, it was time to upgrade.

Why JBake?

Because we’re Java programmers.

There are several good static website generators out there, such as Jekyll (Ruby) and Hugo (Go). We choose JBake (Java), because:

  1. Our website now builds with Maven (mvn generate-resources).

    No need to install anything. Not even JBake. Everyone builds with the same version of JBake, as declared in the pom.xml.

    And it’s fast: even a mvn clean build of 150 output pages only takes 20 seconds on my machine.

  2. It’s all Java underneath.

    Writing conditional expressions is straightforward. The APIs (String.substring(), …) are familiar. Date formatting (d MMMM yyyy) and regular expressions behave as expected.

    And most importantly, error messages are clear.

For 8 years, I wrote the website with Awestruct (Ruby). But I never took the time to decently learn Ruby, so every change entailed hours of trial and error. I couldn’t just read the error message and fix it. This isn’t Ruby’s fault. It was because I never took a few days to actually learn Ruby. With JBake, I fix errors in a fraction of time: no more trial and error.

What Is JBake?

JBake is a static website generator with many options:

  • Build with Maven or Gradle.

    We choose Maven because all our repos build with Maven (although two OptaPlanner Quickstarts also build with Gradle because OptaPlanner supports Gradle too).

  • Write content in Asciidoc, Markdown, or HTML.

    We choose Asciidoc because it’s richer and more reliable than Markdown. Also, all our documentation is written in Asciidoc.

  • Create templates with Freemarker, Thymeleaf, or Groovy.

    We choose Freemarker because it’s a powerful, battle-tested templating engine.

Tips and Tricks

These are common tasks to build an advanced static website and how to implement each task in JBake-Freemarker. You might even call these JBake Design Patterns:

Use a Macro To Render Shared Content

Almost all our templates show the same Latest releases panel:

latest release

A Freemarker template is perfect to avoid repeating yourself (DRY):

  1. Create templates/macros.ftl with a macro that outputs the HTML:

    <#macro latestReleases>
        <div class="panel panel-default">
            <div class="panel-heading">Latest release</div>
            ...
        </div>
    </#macro>
  2. Then use it in the *.ftl templates:

    <#import "macros.ftl" as macros>
    ...
    <div class="row">
        <div class="col-md-9">
            ...
        </div>
        <div class="col-md-3">
            <@macros.latestReleases/>
        </div>
    </div>

Use Data Files To Add Videos, Events, or Other Volatile Data

Some data changes too often to maintain in a content or template file:

Video Files

A data file, for example, a simple *.yml file works well to hold such volatile data:

  1. Create data/videos.yml:

    - youtubeId: blK7gxqu2B0
    title: "Unit testing constraints"
    ...
    
    - youtubeId: gIaHtATz6n8
    title: "Maintenance scheduling"
    ...
    
    - youtubeId: LTkoaBk-P6U
    title: "Vaccination appointment scheduling"
    ...
  2. Then use it in ftl templates:

    <#assign videos = data.get('videos.yml').data>
    
    <div class="panel panel-default">
        <div class="panel-heading">Latest videos</div>
        <div class="panel-body">
            <ul>
                <#list videos[0..6] as video>
                    <li>
                        <a href="https://youtu.be/${video.youtubeId}">${video.title}</a>
                    </li>
                </#list>
            </ul>
        </div>
    </div>

Layout Inheritance

All HTML pages typically share the same HTML head (metadata), header (navigation) and footer. These fit well into a base.ftl layout, extended by all other templates:

Layout inheritance

Even though most content uses the normalBase.ftl, there’s separate useCaseBase.ftl template for all the use case pages, such as the Vehicle Routing Problem (VRP), Maintenance Scheduling and Shift Rostering.

Use a macro with the <\#nested> to build layout inheritance:

  1. Create templates/base.ftl:

    <#macro layout>
        <html>
            <head>
              ...
            </head>
            <body>
                <div>
                    ... <#-- header -->
                </div>
                <#nested>
                <div>
                  ... <#-- footer -->
                </div>
            </body>
        </html>
    </#macro>
  2. Extend it in templates/useCaseBase.ftl and introduce the custom attribute related_tag:

    <#import "base.ftl" as parent>
    
    <@layout>${content.body}</@layout>
    
    <#macro layout>
        <@parent.layout>
            <h1>${content.title}</h1>
            <#nested>
            <h2>Related videos</h2>
            <#assign videos = data.get('videos.yml').data>
            <#assign relatedVideos = videos?filter(video -> video.tags.contains(content.related_tag))>
            <ul>
                <#list relatedVideos as video>
                    <li><a href="https://youtu.be/${video.youtubeId}">${video.title}</a></li>
                </#list>
            </ul>
        </@parent.layout>
    </#macro>
  3. Create the use case page content/vehicleRoutingProblem.adoc that uses that template and sets that related_tag attribute:

    = Vehicle Routing Problem
    :jbake-type: useCaseBase
    :jbake-related_tag: vehicle routing
    
    The Vehicle Routing Problem (VRP) optimizes the routes of delivery trucks,
    cargo lorries, public transportation (buses, taxi's and airplanes)
    or technicians on the road, by improving the order of the visits.
    This routing optimization heavily reduces driving time and fuel consumption compared to manual planning:
    
    ...

Get Started

Try it yourself. To build the www.optaplanner.org website, run these commands:

$ git clone https://github.com/kiegroup/optaplanner-website.git
...
$ cd optaplanner-website
$ mvn clean generate-resources
...
$ firefox target/website/index.html

Or take a look at the source code.

Java (programming language) Apache Maven CI/CD Template Content management system

Published at DZone with permission of Geoffrey De Smet. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • What Are the Best Performance Tuning Strategies for Your SQL Server Indexes?
  • 5 Steps to Create a Successful Agile Release Plan
  • SSH Tutorial: Nice and Easy [Video]
  • The Power of Enum: Make Your Code More Readable and Efficient [Video]

Comments

Java Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • MVB Program
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends:

DZone.com is powered by 

AnswerHub logo