使用 Java 和 Maven (JBake) 生成靜態網站
使用 JBake(「mvn generate-resources」)構建您的靜態網站或部落格。使用布局、宏和數據文件。
我們遷移了整個www.optaplanner.org網站(1399 個文件)以使用 Java 和 Maven,而不是 Ruby 和 Rake 進行構建。從表面上看,什麼都沒有改變。但在源程式碼中,對於我們的 Java 開發人員團隊來說,它是一個遊戲規則改變者。
我們的 Java 團隊現在可以輕鬆地為網站做出貢獻。在完成遷移後的幾個小時內,我們的一位開發人員已經提交了一份不願意用十英尺長的杆子接觸以前的源程式碼的提交。
我們建立了這個網站。
我們在 Java 和 Maven 上構建了這個站點。
我們建立了這個網站。
我們在 JBake 和 Freemarker 上建立了這個網站。
為什麼使用靜態網站生成器?
靜態網站生成器將模板和內容文件轉換為靜態 HTML/JS/CSS 網站。對於我們這樣的項目,這比內容管理系統 (CMS) 有很多優勢:
託管很便宜。GitHub 頁面甚至免費託管靜態網站。
源文件進入 Git 進行備份和歷史記錄。
源文件為純文本格式:
更改以拉取請求的形式出現,以進行適當的審查和 CI 驗證。
源程式碼在我們的 IDE 中是開放的,這鼓勵將它們與程式碼一起重構。這會減少陳舊的內容。
多年來,Awestruct 一直為我們服務。但由於缺乏活動,是時候升級了。
為什麼是 JBake?
因為我們是 Java 程式設計師。
有幾個很好的靜態網站生成器,比如 Jekyll (Ruby) 和 Hugo (Go)。我們選擇JBake (Java),因為:
我們的網站現在使用 Maven ( mvn generate-resources)構建。
無需安裝任何東西。甚至不是 JBake。每個人都使用相同版本的 JBake 構建,如pom.xml.
而且速度很快:即使mvn clean在我的機器上構建 150 個輸出頁面也只需要 20 秒。
.下面全是Java。
編寫條件表達式很簡單。API ( String.substring(), ...) 很熟悉。日期格式 ( d MMMM yyyy) 和正則表達式的行為符合預期。
最重要的是,錯誤消息很清楚。
8 年來,我用 Awestruct (Ruby) 編寫了這個網站。但我從來沒有花時間好好學習 Ruby,所以每次改變都需要數小時的反覆試驗。我不能只是閱讀錯誤消息並修復它。這不是魯比的錯。那是因為我從來沒有花幾天時間來真正學習 Ruby。使用 JBake,我可以在很短的時間內修復錯誤:不再需要反覆試驗。
什麼是 JBake?
JBake 是一個靜態網站生成器,有很多選項:
使用 Maven 或 Gradle 構建。
我們選擇Maven,因為我們所有的 repos 都是用 Maven 構建的(儘管兩個OptaPlanner Quickstarts也用 Gradle 構建,因為 OptaPlanner 也支援 Gradle)。
用 Asciidoc、Markdown 或 HTML 編寫內容。
我們選擇Asciidoc是因為它比 Markdown更豐富、更可靠。此外,我們所有的文檔都是用 Asciidoc 編寫的。
使用 Freemarker、Thymeleaf 或 Groovy 創建模板。
我們選擇Freemarker是因為它是一個強大的、經過實戰考驗的模板引擎。
技巧和竅門
這些是構建高級靜態網站的常見任務以及如何在 JBake-Freemarker 中實現每個任務。您甚至可以將這些JBake 設計模式稱為:
使用宏渲染共享內容
我們幾乎所有的模板都顯示相同的最新版本面板:
最新發布
Freemarker 模板非常適合避免重複自己 (DRY):
templates/macros.ftl使用輸出 HTML 的宏創建:
<#macro latestReleases> <div class="panel panel-default"> <div class="panel-heading">Latest release</div> ... </div> </#macro>
然後在*.ftl模板中使用它:
<#import "macros.ftl" as macros> ... <div class="row"> <div class="col-md-9"> ... </div> <div class="col-md-3"> <@macros.latestReleases/> </div> </div>
使用數據文件添加影片、事件或其他易失性數據
某些數據更改過於頻繁,無法在內容或模板文件中進行維護:
一個數據文件,例如一個簡單的*.yml文件,可以很好地保存這樣的易失性數據:
創建data/videos.yml:
- youtubeId: blK7gxqu2B0
title: "Unit testing constraints"
...
- youtubeId: gIaHtATz6n8
title: "Maintenance scheduling"
...
- youtubeId: LTkoaBk-P6U
title: "Vaccination appointment scheduling"
...
然後在ftl模板中使用它:
<#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="//youtu.be/${video.youtubeId}">${video.title}</a> </li> </#list> </ul> </div> </div>
布局繼承
所有 HTML 頁面通常共享相同的 HTML 頭(元數據)、頁眉(導航)和頁腳。這些非常適合base.ftl布局,由所有其他模板擴展:
儘管大多數內容使用normalBase.ftl,但useCaseBase.ftl所有用例頁面都有單獨的模板,例如車輛路線問題 (VRP)、維護計劃和輪班排班。
使用帶有 的宏<\#nested>來構建布局繼承:
創建templates/base.ftl:
<#macro layout> <html> <head> ... </head> <body> <div> ... <#-- header --> </div> <#nested> <div> ... <#-- footer --> </div> </body> </html> </#macro>
擴展它templates/useCaseBase.ftl並引入自定義屬性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="//youtu.be/${video.youtubeId}">${video.title}</a></li> </#list> </ul> </@parent.layout> </#macro>
創建content/vehicleRoutingProblem.adoc使用該模板並設置該related_tag屬性的用例頁面:
= 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:
...
開始
自己試試吧。要構建www.optaplanner.org網站,請運行以下命令:
$ git clone https://github.com/kiegroup/o... ... $ cd optaplanner-website $ mvn clean generate-resources ... $ firefox target/website/index.html
或者看看源程式碼。

