{"id":19243451,"url":"https://github.com/bootique/bootique-mvc","last_synced_at":"2025-08-18T09:10:20.984Z","repository":{"id":57726820,"uuid":"54138284","full_name":"bootique/bootique-mvc","owner":"bootique","description":"MVC framework for Bootique and Mustache Template Engine integration","archived":false,"fork":false,"pushed_at":"2025-08-08T12:37:17.000Z","size":382,"stargazers_count":6,"open_issues_count":1,"forks_count":4,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-08-08T14:36:02.716Z","etag":null,"topics":["bootique","freemarker","mustache","mvc"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bootique.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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,"zenodo":null}},"created_at":"2016-03-17T17:33:10.000Z","updated_at":"2025-08-08T12:37:20.000Z","dependencies_parsed_at":"2024-04-04T13:57:36.829Z","dependency_job_id":"8ccd493d-83b1-434c-a89c-c863133f4c95","html_url":"https://github.com/bootique/bootique-mvc","commit_stats":null,"previous_names":["nhl/bootique-mvc"],"tags_count":27,"template":false,"template_full_name":null,"purl":"pkg:github/bootique/bootique-mvc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bootique%2Fbootique-mvc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bootique%2Fbootique-mvc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bootique%2Fbootique-mvc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bootique%2Fbootique-mvc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bootique","download_url":"https://codeload.github.com/bootique/bootique-mvc/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bootique%2Fbootique-mvc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270506006,"owners_count":24596506,"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","status":"online","status_checked_at":"2025-08-14T02:00:10.309Z","response_time":75,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["bootique","freemarker","mustache","mvc"],"created_at":"2024-11-09T17:18:03.213Z","updated_at":"2025-08-18T09:10:20.975Z","avatar_url":"https://github.com/bootique.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!--\n  Licensed to ObjectStyle LLC under one\n  or more contributor license agreements.  See the NOTICE file\n  distributed with this work for additional information\n  regarding copyright ownership.  The ObjectStyle LLC licenses\n  this file to you under the Apache License, Version 2.0 (the\n  \"License\"); you may not use this file except in compliance\n  with the License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an\n  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n  KIND, either express or implied.  See the License for the\n  specific language governing permissions and limitations\n  under the License.\n  --\u003e\n\n[![build test deploy](https://github.com/bootique/bootique-mvc/actions/workflows/maven.yml/badge.svg)](https://github.com/bootique/bootique-mvc/actions/workflows/maven.yml)\n[![Maven Central](https://img.shields.io/maven-central/v/io.bootique.mvc/bootique-mvc.svg?colorB=brightgreen)](https://search.maven.org/artifact/io.bootique.mvc/bootique-mvc/)\n\nA basic MVC web framework for [Bootique](http://bootique.io) for processing requests and responding with \ntemplate-generated views. Implemented on top of JAX-RS, specifically [bootique-jersey](https://github.com/bootique/bootique-jersey)). \nbootique-mvc can work with multiple template engines, providing integration with [Mustache](https://mustache.github.io/) \nand [FreeMarker](https://freemarker.apache.org) out of the box. \n\nThis framework is suitable for simple HTML UIs, with minimal server-side rendering (e.g. when most of the UI work is \ndone on the client with JavaScript). \n\nCode examples: [bootique-mvc-demo](https://github.com/bootique-examples/bootique-mvc-demo).\n\n## Usage\n### Prerequisites\nInclude ```bootique-bom```:\n```xml\n\u003cdependencyManagement\u003e\n    \u003cdependencies\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eio.bootique.bom\u003c/groupId\u003e\n            \u003cartifactId\u003ebootique-bom\u003c/artifactId\u003e\n            \u003cversion\u003e3.0-RC1\u003c/version\u003e\n            \u003ctype\u003epom\u003c/type\u003e\n            \u003cscope\u003eimport\u003c/scope\u003e\n        \u003c/dependency\u003e\n    \u003c/dependencies\u003e\n\u003c/dependencyManagement\u003e\n```\n\nInclude the flavor of bootique-mvc you are planning to use, e.g. Jakarta / Mustache:\n\n```xml\n\u003cdependency\u003e\n\t\u003cgroupId\u003eio.bootique.mvc\u003c/groupId\u003e\n\t\u003cartifactId\u003ebootique-mvc-jakarta-mustache\u003c/artifactId\u003e\n\u003c/dependency\u003e\n```\n\n### Create HTML page\n\nCreate a \"view\" class extending `AbstractView`. It performs two functions:\n\n* Defines the location of the page template. Pay attention to the view Java package. Usually template file will be \nlocated under the path matching the view package (see the next section on template resolving mechanism).\n* Serves as a \"root context\" during template rendering, providing values for the template variables. So the view is \nalso a holder of the page \"model\". \n\n```java\npackage org.example.view;\n\npublic class SomePageView extends AbstractView {\n\n    private final String firstName;\n    private final String lastName;\n\n    public SomePageView(String firstName, String lastName) {\n        super(\"some-page.mustache\");\n\n        this.firstName = firstName;\n        this.lastName = lastName;\n    }\n    \n    public String getFirstName() {\n        return firstName;\n    }\n\n    public String getLastName() {\n        return lastName;\n    }\n}\n```\n\nConfigure the app to resolve templates relative to a folder on a classpath :\n\n```yaml\nmvc:\n  templateBase: \"classpath:templates\"\n```\n\nNow let's create a Mustache template in the project resources folder under \n`templates/org/example/view/some-page.mustache`.\n\n```\n\u003chtml\u003e\n\u003cbody\u003e\n\u003ch1\u003eHi, {{firstName}} {{lastName}}!\u003c/h1\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\nFinally, create a \"controller\" class, which is a collection of JAX-RS endpoints that return view instances in response \nto user requests. So a single controller can serve multiple \"pages\" (e.g. those that share a common URL path prefix).\n\n```java\n@Path(\"/\")\n@Produces(MediaType.TEXT_HTML)\npublic static class Pages {\n\n    @GET\n    @Path(\"some-page\")\n    public SomePageView somePage(\n            @QueryParam(\"fn\") String firstName, \n            @QueryParam(\"ln\") String lastName) {\n        return new SomePageView(firstName, lastName);\n    }\n}\n```\n\nNow when you hit `/some-page?fn=Joe\u0026ln=Smith`, you'd get a page that says \"hi\".\n\n### Template Resolving\n\nIn the example above we set the template base to be `classpath:templates`. But it can also be set to a filesystem \ndirectory or a URL on a public web server. The only requirement is that a single base is shared by all templates.\nAssuming the base is `classpath:templates`, here are some simple rules for path resolution:\n\n* Template path with no leading forward slash will be prepended with a path corresponding to the view package:\n`some-page.mustache` -\u003e `classpath:templates/org/example/view/some-page.mustache`. \n* Template path starting with a forward slash is resolved directly against `templateBase`:\n`/some-page.mustache` -\u003e `classpath:templates/some-page.mustache`\n* Template path can reference parent directories via `../`:  `../some-page.mustache` -\u003e \n`classpath:templates/org/example/some-page.mustache`. \n* If a parent directory is outside the `templateBase`, an exception is thrown: `../../../../some-page.mustache` -\u003e throws\n* Templates can include other templates (such includes are called \"partials\" in Mustache). The rules for resolving \nincludes are the same as for the root templates.\n\n### Template Caching\n\nBy default `bootique-mvc` would reload a template on every call. This is great in development mode, but is \ngoing to result in poor performance in production. To configure template caching, you'll need to set an extra\nproperty in config. E.g.:\n\n```yaml\nmvc:\n  templateTtl: 1min\n```\n\n_TODO: as of Bootique 3.0.M2, this only works for Mustache, and not Freemarker until [this task](https://github.com/bootique/bootique-mvc/issues/27) is complete._","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbootique%2Fbootique-mvc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbootique%2Fbootique-mvc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbootique%2Fbootique-mvc/lists"}