Spring MVC Theme Switcher Example

In this tutorial we build a Spring MVC theme. You can apply a Spring MVC theme to set the overall look-and-feel of your web application. A theme is a collection of static resources like images, stylesheets etc.., that affect the look and feel of an application.

Project Structure

Make sure your project looks similar to the following structure.

src
|--main
|    +--java
|        +--com
|            +--memorynotfound
|                +--config
|                    |--ServletInitializer.java
|                    |--WebConfig.java
|                +--controller
|                    |--HomeController.java
|    +--resources
|        +--themes
|            |--bright.properties
|            |--dark.properties
|    +--webapp
|        +--themes
|            |--bright.css
|            |--dark.css
|        +--WEB-INF
|            +--views
|                |--index.jsp
pom.xml

Create Theme Files

A Spring MVC theme is a collection of static resources like images and stylesheets. We can optionally also add differentn properties to each theme. Below, we are creating two themes, one called bright and the other called dark.

Add the bright.properties file to the src/main/resources/themes folder.

stylesheet=themes/bright.css

Add the dark.properties file to the src/main/resources/themes folder.

stylesheet=themes/dark.css

Configure Spring MVC Theme Switcher

Because we are serving static resources, we need to add a ResourceHandler. This resource handler will handle static resources from the theme folder. Optionally we can also add caching rules to these resources.

Next, we register a ResourceBundleThemeSource, which is responsible for locating the themes. By setting the basenamePrefix, we can prefix the themes. The dot after the name indicates that this is a directory.

The CookieThemeResolver uses a cookie to select the theme, with fallback to the default theme.

The ThemeChangeInterceptor allows for changing the current theme on every request, via a configurable request parameter.

package com.memorynotfound.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.ui.context.support.ResourceBundleThemeSource;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.theme.CookieThemeResolver;
import org.springframework.web.servlet.theme.ThemeChangeInterceptor;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

@EnableWebMvc
@Configuration
@ComponentScan({"com.memorynotfound"})
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/themes/**").addResourceLocations("/themes/");
    }

    @Bean
    public ResourceBundleThemeSource themeSource(){
        ResourceBundleThemeSource themeSource = new ResourceBundleThemeSource();
        themeSource.setDefaultEncoding("UTF-8");
        themeSource.setBasenamePrefix("themes.");
        return themeSource;
    }

    @Bean
    public CookieThemeResolver themeResolver(){
        CookieThemeResolver resolver = new CookieThemeResolver();
        resolver.setDefaultThemeName("bright");
        resolver.setCookieName("my-theme-cookie");
        return resolver;
    }

    @Bean
    public ThemeChangeInterceptor themeChangeInterceptor(){
        ThemeChangeInterceptor interceptor = new ThemeChangeInterceptor();
        interceptor.setParamName("theme");
        return interceptor;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(themeChangeInterceptor());
    }

    @Bean
    public InternalResourceViewResolver viewResolver(){
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
}

You can find the equivallent Spring MVC theme configuration below.

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/mvc
                           http://www.springframework.org/schema/mvc/spring-mvc.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd ">

    <mvc:annotation-driven />
    <context:component-scan base-package="com.memorynotfound" />

    <mvc:resources mapping="/themes/**" location="/themes/"/>

    <bean id="themeSource" class="org.springframework.ui.context.support.ResourceBundleThemeSource">
        <property name="basenamePrefix" value="themes."/>
        <property name="defaultEncoding" value="UTF-8"/>
    </bean>

    <bean id="themeResolver" class="org.springframework.web.servlet.theme.CookieThemeResolver">
        <property name="defaultThemeName" value="bright"/>
        <property name="cookieName" value="my-theme-cookie"/>
    </bean>
    
    <mvc:interceptors>
        <bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor">
            <property name="paramName" value="theme"/>
        </bean>
    </mvc:interceptors>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    </bean>

</beans>

Creating the Stylesheets

We use a different stylesheet for every theme. The location of the stylesheet is registered in the properties file of the theme.

Add the bright.css file to the src/main/webapp/themes directory.

body {
    color: blue;
    background-color: white;
}

Add the dark.css file to the src/main/webapp/themes directory.

body {
    color: white;
    background-color: black;
}

Spring MVC Theme Switcher Example

This page includes two links to simply switch between different themes. The themes are included using the <spring:theme/> element. This elements will display the current theme.

<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<html>
<head>
    <link rel="stylesheet" href="<spring:theme code='stylesheet'/>" type="text/css" />
    <title>Spring MVC ThemeResolver Example</title>
</head>
<body>

<h3>Spring MVC ThemeResolver Example</h3>
theme: <a href="?theme=bright">bright</a> | <a href="?theme=dark">dark</a>

</body>
</html>

Demo

URL: http://localhost:8081/spring-mvc-theme/?theme=bright

spring mvc theme switcher bright

URL: http://localhost:8081/spring-mvc-theme/?theme=dark

spring mvc theme switcher dark

If you inspect the cookies, you can find the my-theme-cookie with the correct value of the current theme.

spring mvc theme switcher cookie

References

Download

You may also like...