Spring WebJars tutorial
last modified October 18, 2023
Spring WebJars tutorial shows how to use WebJars in a Spring web application.
Spring is a popular Java application framework for creating enterprise applications.
Webjars
WebJars are client-side web libraries (e.g. jQuery or Semantic UI) packaged into JAR (Java Archive) files. WebJars automate the work with frontend libraries and assets.
Spring WebJar example
In the following example, we use Semantic-UI WebJar. Semantic-UI is a popular CSS framework.
pom.xml src ├───main │ ├───java │ │ └───com │ │ └───zetcode │ │ ├───config │ │ │ MyWebInitializer.java │ │ │ WebConfig.java │ │ └───controller │ │ MyController.java │ └───resources │ │ logback.xml │ └───templates │ index.html └───test └───java
This is the project structure.
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zetcode</groupId> <artifactId>WebJarEx</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <spring-version>5.1.4.RELEASE</spring-version> <thymeleaf-version>3.0.11.RELEASE</thymeleaf-version> </properties> <dependencies> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>Semantic-UI</artifactId> <version>2.4.1</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>webjars-locator</artifactId> <version>0.34</version> </dependency> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> <version>${thymeleaf-version}</version> </dependency> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf</artifactId> <version>${thymeleaf-version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.3.2</version> </plugin> </plugins> </build> </project>
In the pom.xml
we have the project dependencies.
<dependency> <groupId>org.webjars</groupId> <artifactId>Semantic-UI</artifactId> <version>2.4.1</version> </dependency>
We use the Semantic-UI WebJar.
<dependency> <groupId>org.webjars</groupId> <artifactId>webjars-locator</artifactId> <version>0.34</version> </dependency>
The webjars-locator
allows us to refer to the assets without
referring to the version of the asset, which is automatically detected.
<?xml version="1.0" encoding="UTF-8"?> <configuration> <logger name="org.springframework" level="ERROR"/> <logger name="com.zetcode" level="INFO"/> <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n </Pattern> </encoder> </appender> <root> <level value="INFO" /> <appender-ref ref="consoleAppender" /> </root> </configuration>
This is the logback.xml
configuration
package com.zetcode.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.FrameworkServlet; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; @Configuration public class MyWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return null; } @Override protected Class<?>[] getServletConfigClasses() { return new Class[]{WebConfig.class}; } @Override protected String[] getServletMappings() { return new String[]{"/"}; } }
MyWebInitializer
initializes the Spring web application. It contains one
configuration class: WebConfig
.
package com.zetcode.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.thymeleaf.spring5.SpringTemplateEngine; import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; import org.thymeleaf.spring5.view.ThymeleafViewResolver; @Configuration @EnableWebMvc @ComponentScan(basePackages = {"com.zetcode"}) public class WebConfig implements WebMvcConfigurer { @Autowired private ApplicationContext applicationContext; @Bean public SpringResourceTemplateResolver templateResolver() { var templateResolver = new SpringResourceTemplateResolver(); templateResolver.setApplicationContext(applicationContext); templateResolver.setPrefix("classpath:templates/"); templateResolver.setSuffix(".html"); return templateResolver; } @Bean public SpringTemplateEngine templateEngine() { var templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResolver(templateResolver()); templateEngine.setEnableSpringELCompiler(true); return templateEngine; } @Bean public ViewResolver viewResolver() { var resolver = new ThymeleafViewResolver(); var registry = new ViewResolverRegistry(null, applicationContext); resolver.setTemplateEngine(templateEngine()); registry.viewResolver(resolver); return resolver; } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry .addResourceHandler("/webjars/**") .addResourceLocations("/webjars/").resourceChain(false); } @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } }
The WebConfig
configures the Thymeleaf template engine, tells
Spring where to look for WebJars and enables forwarding to the default servlet
for handling of static resources.
@Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry .addResourceHandler("/webjars/**") .addResourceLocations("/webjars/").resourceChain(false); }
We will refer to the WebJars via the /webjars/
path.
The resourceChain
method must be called for version-agnostic
WebJars.
package com.zetcode.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import java.util.List; @Controller public class MyController { @GetMapping(value = "/") public String home(Model model) { var words = List.of("wood", "star", "cloud", "water", "river", "spring"); model.addAttribute("words", words); return "index"; } }
MyController
contains one route for the home page. We send some
data to the template. The data will be presented in an HTML table, which will
be styled with Semantic-UI.
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Home page</title> <link rel="stylesheet" th:href="@{/webjars/Semantic-UI/semantic.css}"> </head> <body> <section class="ui container"> <h2>English words</h2> <table class="ui striped celled table"> <thead> <tr> <th>Index</th> <th>Word</th> </tr> </thead> <tbody> <tr th:each="word : ${words}"> <td th:text="${wordStat.index + 1}">Index</td> <td th:text="${word}">A word</td> </tr> </tbody> </table> </section> </body> </html>
This is the home page.
<link rel="stylesheet" th:href="@{/webjars/Semantic-UI/semantic.css}">
We link to the semantic.css
file, which comes from the WebJar.
<table class="ui striped celled table">
The CSS classes come from the Semantic-UI library.
In this article we have created used a Semantic-UI WebJar to style an HTML table.
Author
List all Spring tutorials.