{"id":20957024,"url":"https://github.com/spilth/annotated-spring-episode-003","last_synced_at":"2025-06-13T03:32:36.318Z","repository":{"id":136684021,"uuid":"41829702","full_name":"spilth/annotated-spring-episode-003","owner":"spilth","description":"Web Application Layouts with Freemarker, WebJars \u0026 Bootstrap","archived":false,"fork":false,"pushed_at":"2016-12-17T15:58:33.000Z","size":4,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-03-13T06:12:54.899Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://www.annotatedspring.com/episodes/3/web-application-layouts-with-freemarker-webjars-and-bootstrap","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/spilth.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-09-02T21:55:56.000Z","updated_at":"2024-10-24T18:23:42.000Z","dependencies_parsed_at":null,"dependency_job_id":"34eb404c-4cb1-4172-8a75-2bade7325528","html_url":"https://github.com/spilth/annotated-spring-episode-003","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/spilth/annotated-spring-episode-003","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spilth%2Fannotated-spring-episode-003","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spilth%2Fannotated-spring-episode-003/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spilth%2Fannotated-spring-episode-003/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spilth%2Fannotated-spring-episode-003/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/spilth","download_url":"https://codeload.github.com/spilth/annotated-spring-episode-003/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spilth%2Fannotated-spring-episode-003/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259573839,"owners_count":22878581,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-19T01:29:16.975Z","updated_at":"2025-06-13T03:32:36.263Z","avatar_url":"https://github.com/spilth.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Web Application Layouts with Freemarker, WebJars \u0026 Bootstrap\n\n## Overview\n\nWhen building a web app you’ll likely want to have a consisted layout and navigation across your site. For internal applications, frameworks like [Bootstrap](http://getbootstrap.com) make it easy to have something attractive and consistent out of the box.\n\nFront-end developers use tools like [Bower](http://bower.io) to automatically manage the frameworks, libraries and assets they use in their projects. A similar format called [WebJars](http://www.webjars.org) exists for Java web apps which packages client-side libraries into JAR files.\n\nWe’re going to create a couple of simple pages that use the same layout by making use of [Freemarker](http://freemarker.org)’s macros with Bootstrap provided via a a WebJar.\n\n## First Steps\n\nFirst we create a Spring web app with Freemarker as a dependency\n\n    $ spring init web-layout -d=web,freemarker\n\nThen we create a simple controller that serves up two pages:\n\n    package demo;\n\n    import org.springframework.stereotype.Controller;\n    import org.springframework.web.bind.annotation.RequestMapping;\n\n    @Controller\n    public class PagesController {\n        @RequestMapping(\"/one\")\n        public String one() {\n            return \"one\";\n        }\n\n        @RequestMapping(\"/two\")\n        public String two() {\n            return \"two\";\n        }\n    }\n\nNext, we create a template for each of the actions. Here is page one:\n\n    \u003cp\u003eThis is page one.\u003c/p\u003e\n\nAnd here is page two:\n\n    \u003cp\u003eThis is page two.\u003c/p\u003e\n\nIf we start up our server, we can get to the two pages by going directly to their URLs.\n\n    $ mvn spring-boot:run\n\n- \u003chttp://localhost:8080/one\u003e\n- \u003chttp://localhost:8080/two\u003e\n\nTo make these pages look nicer and consistent, we’ll add Bootstrap and create a layout Freemarker macro.\n\n## Adding Bootstrap with WebJars\n\nThe [WebJars web site](http://www.webjars.org) makes it easy to search for a project and copy the dependency syntax needed by your build tool. We switch the build tool to Maven and then search for bootstrap. We then copy that XML into our `pom.xml`.\n\n    \u003cdependency\u003e\n        \u003cgroupId\u003eorg.webjars\u003c/groupId\u003e\n        \u003cartifactId\u003ebootstrap\u003c/artifactId\u003e\n        \u003cversion\u003e3.3.5\u003c/version\u003e\n    \u003c/dependency\u003e\n\nTo create the macro we’ll make a `layout` directory under the `templates` directory and create a Freemarker template named `application.ftl`. Inside this file we define a macro named `layout` and add the HTML for the layout of our site.\n\n    \u003c#macro layout\u003e\n    \u003c!doctype html\u003e\n    \u003chtml lang=\"en\"\u003e\n    \u003chead\u003e\n        \u003cmeta charset=\"utf-8\"\u003e\n        \u003ctitle\u003eExample\u003c/title\u003e\n        \u003clink rel='stylesheet' href='/webjars/bootstrap/3.3.5/css/bootstrap.min.css'\u003e\n    \u003c/head\u003e\n\n    \u003cbody\u003e\n        \u003cnav class=\"navbar navbar-default\"\u003e\n            \u003cdiv class=\"container\"\u003e\n                \u003cdiv id=\"navbar\" class=\"collapse navbar-collapse\"\u003e\n                    \u003cul class=\"nav navbar-nav\"\u003e\n                        \u003cli\u003e\u003ca href=\"/one/\"\u003eOne\u003c/a\u003e\u003c/li\u003e\n                        \u003cli\u003e\u003ca href=\"/two/\"\u003eTwo\u003c/a\u003e\u003c/li\u003e\n                    \u003c/ul\u003e\n                \u003c/div\u003e\n            \u003c/div\u003e\n        \u003c/nav\u003e\n\n        \u003cdiv class=\"container\"\u003e\n            \u003ch1\u003eExample\u003c/h1\u003e\n            \u003c#nested\u003e\n        \u003c/div\u003e\n    \u003c/body\u003e\n    \u003c/html\u003e\n    \u003c/#macro\u003e\n\nSince we want each page to provide its own contents to the layout, we use the `\u003c#nested\u003e` directive to render the page itself within the layout.\n\nTo make it easy to the macro on every page in our app, we can configure Freemarker to auto include the template with this layout macro. In `application.properties` we set:\n\n    spring.freemarker.settings.auto_include=layout/application.ftl\n\nNow we can update our page templates to make use of the macro. Here is page one:\n\n    \u003c@layout\u003e\n        \u003cp\u003eThis is page one.\u003c/p\u003e\n    \u003c/@layout\u003e\n\nAnd here is page two:\n\n    \u003c@layout\u003e\n        \u003cp\u003eThis is page two.\u003c/p\u003e\n    \u003c/@layout\u003e\n\nIf we restart our server and check out our pages, they should have the same look and feel now.\n\n    $ mvn spring-boot:run\n\n## Page Titles \u0026 Headers\n\nCurrently both pages have the same title and header. It would be nice if we could set additional content for each page other than the main body.\n\nWe can go back into our macro and add a parameter for the title and then reference that in our layout.\n\n    \u003c#macro application title\u003e\n    \u003c!doctype html\u003e\n    \u003chtml lang=\"en\"\u003e\n    \u003chead\u003e\n        \u003cmeta charset=\"utf-8\"\u003e\n        \u003ctitle\u003e${title}\u003c/title\u003e\n        \u003clink rel='stylesheet' href='/webjars/bootstrap/3.3.5/css/bootstrap.min.css'\u003e\n    \u003c/head\u003e\n\n    \u003cbody\u003e\n        \u003cnav class=\"navbar navbar-default\"\u003e\n            \u003cdiv class=\"container\"\u003e\n                \u003cdiv id=\"navbar\" class=\"collapse navbar-collapse\"\u003e\n                    \u003cul class=\"nav navbar-nav\"\u003e\n                        \u003cli\u003e\u003ca href=\"/one/\"\u003eOne\u003c/a\u003e\u003c/li\u003e\n                        \u003cli\u003e\u003ca href=\"/two/\"\u003eTwo\u003c/a\u003e\u003c/li\u003e\n                    \u003c/ul\u003e\n                \u003c/div\u003e\n            \u003c/div\u003e\n        \u003c/nav\u003e\n\n        \u003cdiv class=\"container\"\u003e\n            \u003ch1\u003e${title}\u003c/h1\u003e\n            \u003c#nested\u003e\n        \u003c/div\u003e\n    \u003c/body\u003e\n    \u003c/html\u003e\n    \u003c/#macro\u003e\n\nThen we assign a value to that parameter when we use the macro in each page. Here is page one:\n\n    \u003c@layout title=\"One\"\u003e\n        \u003cp\u003eThis is page one.\u003c/p\u003e\n    \u003c/@layout\u003e\n\nAnd here is page two:\n\n    \u003c@layout title=\"Two\"\u003e\n        \u003cp\u003eThis is page two.\u003c/p\u003e\n    \u003c/@layout\u003e\n\nNext: [CRUD Web App: Part 1 - Create \u0026 Read](https://github.com/spilth/annotated-spring-episode-004)\n\n## Resources\n\n- http://freemarker.org\n- http://freemarker.org/docs/ref_directive_macro.html\n- http://getbootstrap.com\n- http://www.webjars.org\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspilth%2Fannotated-spring-episode-003","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspilth%2Fannotated-spring-episode-003","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspilth%2Fannotated-spring-episode-003/lists"}