I was exploring a little Spring Boot, and I was having a look at some frontend libraries - which I admit I have almost never seen :)
I am probably doing some stupid mistake that makes Bootstrap not working. I am trying to set up a header page. As I hate doing simple things, I am using Spring Boot, Webjars and Thymeleaf. All for the first time. But it seems everything is all right, and I cannot understand what is wrong.
First of all, here is the Gradle dependencies. I am using spring 2.0.0.M7. I cut the applied plugins repositories and group/version
buildscript { ext { springBootVersion = '2.0.0.M7' } repositories { mavenCentral() maven { url "https://repo.spring.io/snapshot" } maven { url "https://repo.spring.io/milestone" } } dependencies { classpath group: 'org.springframework.boot', name: 'spring-boot-gradle-plugin', version: "${springBootVersion}" } } // ##### COMPILE DEPENDENCIES // DATABASE compile group: 'mysql', name: 'mysql-connector-java' // SPRING compile group: 'org.springframework.boot', name: 'spring-boot-devtools' compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa' compile group: 'org.springframework.boot', name: 'spring-boot-starter-json' compile group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf' compile group: 'org.springframework.boot', name: 'spring-boot-starter-web' // THYMELEAF compile group: 'nz.net.ultraq.thymeleaf', name: 'thymeleaf-layout-dialect', version: '2.2.2' // WEB JAVASCRIPT LIBS compile group: 'org.webjars', name: 'webjars-locator', version: '0.32-1' compile group: 'org.webjars', name: 'bootstrap', version: '4.0.0-beta.3' I am using webjars locator. I liked this approach because I have complete control of my libraries here, and I do not have to put version numbers on the application.
I have then set up the resource handler to retrieve the webjars, and the spring layout dialect...
@Bean WebMvcConfigurer configurer() { return new WebMvcConfigurer() { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry .addResourceHandler("/webjars/**") .addResourceLocations("/webjars/") .resourceChain(false); } }; } @Bean LayoutDialect layoutDialect() { return new LayoutDialect(); } ... the Spring application...
@SpringBootApplication(scanBasePackages = { "it.aegidea.wolf" }) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ... the controller...
@Controller public class HomepageController { @RequestMapping(value = "/", method = RequestMethod.GET) public String getHomepage() { return "homepage"; } } ... the overall layout...
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"> <head> <!--/* Each token will be replaced by their respective titles in the resulting page. */--> <title layout:title-pattern="$LAYOUT_TITLE - $CONTENT_TITLE">Task List</title> <link rel="stylesheet" type="text/css" href="/webjars/bootstrap/css/bootstrap.min.css" /> </head> <body> <div th:include="commons/header :: page-header"></div> <div class="container"> <div layout:fragment="content"> </div> </div> <!-- Injected --> <script src="/webjars/jquery/jquery.min.js"></script> <script src="/webjars/popper.js/dist/umd/popper.js"></script> <script src="/webjars/bootstrap/js/bootstrap.min.js"></script> </body> ... the header...
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <body> <nav class="navbar navbar-default navbar-fixed-top" th:fragment="page-header"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#title-collapse" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Brand</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="title-collapse"> <ul class="nav navbar-nav"> <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li> <li><a href="#">Link</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="#">Separated link</a></li> <li role="separator" class="divider"></li> <li><a href="#">One more separated link</a></li> </ul> </li> </ul> <form class="navbar-form navbar-left"> <div class="form-group"> <input type="text" class="form-control" placeholder="Search"> </div> <button type="submit" class="btn btn-default">Submit</button> </form> <ul class="nav navbar-nav navbar-right"> <li><a href="#">Link</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="#">Separated link</a></li> </ul> </li> </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> </body> </html> ... and finally, the homepage.
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{commons/layout}"> <head> <meta charset="UTF-8" /> <title>Wolf</title> </head> <body> <div layout:fragment="content"> <p th:text="'Hello World!'" >Hello World!</p> <div class="btn-group"> <button type="button" class="btn btn-success">This is a success button</button> <button type="button" class="btn btn-warning">This is a warning button</button> <button type="button" class="btn btn-danger">This is a danger button</button> </div> </div> </body> </html> The (weird) effect is that style get correctly applied to the buttons in the homepage, but not to the navbar.
What I've tried to do is
- trying to include bootstrap, popper and jquery with direct links (taken from Bootstrap homepage)
- trying to directly include the header into the homepage, just after
I am 100% sure I am doing some incredibly stupid mistake, but I've probably seen the code so many times that I cannot see what I am doing wrong.
Thanks for anyone's help :)
Lorenzo