Spring MVC Themes Tutorial

By Arvind Rai, June 27, 2019
On this page we will walk through the Spring MVC Themes tutorial with examples using JavaConfig. Spring MVC provides custom theme resolution. We can give the different theme options to our users in web application that can be handled in Spring MVC in easy way. This is same as Spring MVC internationalization and localization handling. The main API which handles themes are ThemeSource, ThemeResolver and ThemeChangeInterceptor.
In our theme example we have also accommodated the code of spring MVC internationalization and localization and for the explanation, find the link here. To understand the spring MVC theme we will go step by step.

Project Structure in Eclipse

Find the demo project structure in eclipse.
Spring MVC Themes Tutorial and Example with ThemeResolver using  Annotation

Gradle File

Find the Gradle file used in our example.
build.gradle
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'war'
archivesBaseName = 'concretepage'
version = '1' 
repositories {
    mavenCentral()
}
dependencies {
    compile 'org.springframework.boot:spring-boot-starter-web:1.2.2.RELEASE'
    compile 'jstl:jstl:1.2'
    providedCompile 'org.springframework.boot:spring-boot-starter-tomcat:1.2.2.RELEASE'
} 

Configuration Class for Spring MVC Themes

In java configuration create bean for ThemeSource, ThemeResolver and register ThemeChangeInterceptor to achieve spring MVC themes.
AppConfiguration.java
package com.concretepage.config;  
import java.util.Locale;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.ui.context.ThemeSource;
import org.springframework.ui.context.support.ResourceBundleThemeSource;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.ThemeResolver;
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.i18n.CookieLocaleResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.theme.CookieThemeResolver;
import org.springframework.web.servlet.theme.ThemeChangeInterceptor;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration 
@ComponentScan("com.concretepage") 
@EnableWebMvc
public class AppConfiguration extends WebMvcConfigurerAdapter {  
    @Bean  
    public InternalResourceViewResolver viewResolver() {  
	InternalResourceViewResolver resolver = new InternalResourceViewResolver();  
        resolver.setPrefix("/WEB-INF/views/");  
        resolver.setSuffix(".jsp");
        return resolver;  
    }
    /* Theme specific start */
    @Bean
    public ThemeSource themeSource() {
    	ResourceBundleThemeSource source = new ResourceBundleThemeSource();
    	source.setBasenamePrefix("hello-");
    	return source;
    }
    @Bean 
    public ThemeResolver themeResolver(){
    	CookieThemeResolver resolver = new CookieThemeResolver();
    	resolver.setCookieMaxAge(2400);
    	resolver.setCookieName("mythemecookie");
    	resolver.setDefaultThemeName("theme1");
    	return resolver;
    }
    /* End */
    
    /*Internationalization and Localization specific: start*/
    @Bean
    public MessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setBasename("/i18/usermsg");
        messageSource.setDefaultEncoding("UTF-8");
        return messageSource;
    }
    @Bean
    public LocaleResolver localeResolver(){
	CookieLocaleResolver resolver = new CookieLocaleResolver();
	resolver.setDefaultLocale(new Locale("en"));
	resolver.setCookieName("myLocaleCookie");
	resolver.setCookieMaxAge(4800);
	return resolver;
    }
    /* End */
    
    //Register interceptors
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
	//Internationalization and Localization specific
	LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
	interceptor.setParamName("mylocale");
	registry.addInterceptor(interceptor);
	//Theme specific
	ThemeChangeInterceptor themeInterceptor = new ThemeChangeInterceptor();
	themeInterceptor.setParamName("mytheme");
	registry.addInterceptor(themeInterceptor);
    }
    //Used to access CSS resource
    @Override
    public void addResourceHandlers(final ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    }
} 
Find the web application initializer.
Initializer.java
package com.concretepage.config;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
public class Initializer implements WebApplicationInitializer {
   public void onStartup(ServletContext servletContext) throws ServletException {  
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();  
        ctx.register(AppConfiguration.class);  
        ctx.setServletContext(servletContext);    
        Dynamic dynamic = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));  
        dynamic.addMapping("/");  
        dynamic.setLoadOnStartup(1);  
   }  
} 

ThemeSource

org.springframework.ui.context.ThemeSource is an interface that resolves themes. It enables parameterization and internalization of themes. ResourceBundleThemeSource is the implementation of ThemeSource. It finds a java ResourceBundle per theme. We need to tell it file base name using which ResourceBundleThemeSource resolves the ResourceBundle. We need to create bean with spring reserved name as themeSource.
@Bean
public ThemeSource themeSource() {
   ResourceBundleThemeSource source = new ResourceBundleThemeSource();
   source.setBasenamePrefix("hello-");
   return source;
} 
Here we have set file base name as hello-. File name should start with this prefix.

ThemeResolver

org.springframework.web.servlet.ThemeResolver is an interface that is used for theme resolution strategies. We need to create a bean with the spring reserved name themeResolver. The implementations of this interface can handle theme resolution via request and changes in theme via request and response. The implementation classes are based on session and cookie etc that are given as follows.

FixedThemeResolver: This is the default implementation of ThemeResolver which uses the fixed configured default theme. It can be set by defaultThemeName() method. The default name is theme. It does not support setThemeName because fixed cannot be changed.

CookieThemeResolver: This is the cookie based implementation of ThemeResolver. We need to create bean for CookieThemeResolver and set cookie name, cookie max age, default theme name etc. For custom theme setting, a cookie is set on browser and till the next change and expiry time, cookie value remains in browser and selected theme is displayed onwards. Cookie based approach is useful in stateless websites. Find the bean creation for using CookieThemeResolver.
@Bean 
public ThemeResolver themeResolver(){
   CookieThemeResolver resolver = new CookieThemeResolver();
   resolver.setCookieMaxAge(2400);
   resolver.setCookieName("mythemecookie");
   resolver.setDefaultThemeName("theme1");
   return resolver;
} 
Here we have set cookie name as mythemecookie that will contain the custom theme name. The default theme properties file name will be hello-theme1.properties.

SessionThemeResolver: This is the session based implementation of ThemeResolver. This approach is useful where the application has user session. In case of theme custom setting, a theme attribute is set in user session. The theme attribute name can be overridden by using setThemeName(). We can create the bean as below.
@Bean 
public ThemeResolver themeResolver(){
   SessionThemeResolver resolver = new SessionThemeResolver();
   resolver.setDefaultThemeName("theme1");
   return resolver;
} 
Here we have set the default theme name as theme1, so the full name will be hello-theme1.properties.

ThemeChangeInterceptor

org.springframework.web.servlet.theme.ThemeChangeInterceptor is an interceptor that allows to change theme per request. This is achieved by a configurable request parameter. The default request parameter is theme. Find the code how to register ThemeChangeInterceptor.
LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
ThemeChangeInterceptor themeInterceptor = new ThemeChangeInterceptor();
themeInterceptor.setParamName("mytheme");
registry.addInterceptor(themeInterceptor); 
Here the default parameter name has been overridden to be mytheme. So while changing theme, we can use query string as
? mytheme= theme1: Applies the theme hello-theme1.properties
? mytheme= theme2: Applies the theme hello-theme2.properties

Resource Handling

For the demo, we need some CSS file, and to include these resources, we need to tell spring about the URL pattern of resources. As our CSS file has been kept in resources\css, the URL pattern can be defined as below in the code.
@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
} 
The method addResourceHandlers() has been overridden from WebMvcConfigurerAdapter.

Create CSS

For the demo we are using following CSS files.
style1.css
H3 {
  COLOR: green; FONT-FAMILY: sans-serif; FONT-SIZE: 20pt;
} 

style2.css
H3 {
   COLOR: red; FONT-FAMILY: arial; FONT-SIZE: 20pt;
} 

Create Properties File for Themes

Find the properties file used in our demo.
hello-theme1.properties
styleSheet=resources/css/style1.css
background= red 

hello-theme2.properties
styleSheet=resources/css/style2.css
background= Green 

Create Properties File for i18n

Find the properties file for i18n.
usermsg_en.properties
user.title= Fill User Form
user.name= Enter Name
user.age= Enter Age
user.submit= Submit
user.success= You have successfully submitted the form 

usermsg_de.properties
user.title= Füllen User Form
user.name= Name eingeben
user.age= Geben Alter
user.submit= einreichen
user.success= Sie haben die Form eingereicht 

Create JSP File

Find the JSP file being used in our demo. We have created two links that will change the theme.
userform.jsp
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html>
   <head>
        <title><spring:message code="user.title"/></title>
        <link rel="stylesheet" href="<spring:theme code='styleSheet'/>" type="text/css"/>
   </head>
<body bgcolor="<spring:theme code='background'/>">
  Change language: <a href="user?mylocale=en">English </a> | <a href="user?mylocale=de">German </a><br/><br/>
  Change theme: <a href="user?mytheme=theme1">Theme 1 </a> | <a href="user?mytheme=theme2"> Theme 2 </a>
  <h3> <spring:message code="user.title"/></h3>
<table>	
  <form:form action="save" method="post" commandName="user">
	<tr><td><spring:message code="user.name"/>:</td> <td><form:input  path="name"/> </td> </tr> 
	<tr> <td> <spring:message code="user.age"/> :</td> <td><form:input path="age"/> </td> </tr> 
	<tr> <td colspan=2>  
	   <spring:message code="user.submit" var="valSubmit"></spring:message> 
	   <input type="submit" value="${valSubmit}">
	</td></tr>
  </form:form>
 </table>
</body>
</html> 

success.jsp
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<html>
   <head>
        <title><spring:message code="user.title"/></title>
        <link rel="stylesheet" href="<spring:theme code='styleSheet'/>" type="text/css"/>
   </head>
<body bgcolor="<spring:theme code='background'/>">
  Change language: <a href="user?mylocale=en">English </a> | <a href="user?mylocale=de">German </a><br/><br/>
  Change theme: <a href="user?mytheme=theme1">Theme 1 </a> | <a href="user?mytheme=theme2"> Theme 2 </a>
  
  <h3> <spring:message code="user.success"/></h3>
</body>
</html> 

Create Controller

Find the controller used in our example.
UserController.java
package com.concretepage.controller;
import java.util.Locale;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.concretepage.bean.User;
@Controller
public class UserController {
	@RequestMapping(value="/user", method = RequestMethod.GET)
	public ModelAndView user(Locale locale){
		return new ModelAndView("userform","user",new User());
	}
	@RequestMapping(value = "/save", method = RequestMethod.POST)
	public String  save(@ModelAttribute("user") User user) {
		return "success";
	}
} 
Find the bean used in our example.
User.java
package com.concretepage.bean;
public class User {
    private String name;
    private Integer age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
} 

Output

Deploy the code in tomcat 8 and access the URL localhost:8080/concretepage-1/user
By default the hello-theme1.properties file will be loaded. We will get the output as given below.
Spring MVC Themes Tutorial and Example with ThemeResolver using  Annotation
This output can also be achieved by the URL http://localhost:8080/concretepage-1/user?mytheme=theme1 On submit the page, we will get output as below.
Spring MVC Themes Tutorial and Example with ThemeResolver using  Annotation
To change the theme, click on theme link. The URL will be http://localhost:8080/concretepage-1/user?mytheme=theme2
We will get the output as below.
Spring MVC Themes Tutorial and Example with ThemeResolver using  Annotation
And on submit, the output will be as below.
Spring MVC Themes Tutorial and Example with ThemeResolver using  Annotation
As we are using CookieThemeResolver in our demo, so our defined cookie mythemecookie will be set in browser.
Spring MVC Themes Tutorial and Example with ThemeResolver using  Annotation

Change Locale and Theme Together

To change locale and theme together we can use locale and theme parameter together in query string that will look like.
http://localhost:8080/concretepage-1/user?mytheme=theme2&mylocale=en
http://localhost:8080/concretepage-1/user?mytheme=theme2&mylocale=de
http://localhost:8080/concretepage-1/user?mytheme=theme1&mylocale=de
http://localhost:8080/concretepage-1/user?mytheme=theme1&mylocale=en

Now I am done. Happy Learning!

Download Complete Source Code

POSTED BY
ARVIND RAI
ARVIND RAI







©2024 concretepage.com | Privacy Policy | Contact Us