Resolving Theme Based On Domain Names On Spring Boot / Thymeleaf

Here’s my situation, I have myapp.firstdomain.com and myapp.seconddomain.com and I want my app to be styled / branded differently according to which domain used to access the app.

To keep things simple, each theme would have its own properties file with corresponding values. For example:

# src/main/resources/themes/firstdomain.properties
theme_css=/public/css/firstdomain.css
# src/main/resources/themes/seconddomain.properties
theme_css=/public/css/seconddomain.css

Next we have to register a ResourceBundleThemeSource. This tells spring where the theme specific properties file are located (in this instance we place them on themes/ folder on classpath root).

In Spring Boot, since I used automatic configuration for the web application context, additional customization has to be done via WebMvcConfigurerAdapter


public class WebMvcConfig extends WebMvcConfigurerAdapter {


  public ThemeSource themeSource() {
    ResourceBundleThemeSource themeSource = new ResourceBundleThemeSource();
    themeSource.setBasenamePrefix("themes/");
    return themeSource;
  }

}

Next I need to create a ThemeResolver bean that can determine the theme based on domain names. In this instance since I used a reverse proxy, I used X-Forwarded-For HTTP header to determine the hostname, but you can simply use Host header otherwise.

This ThemeResolver keeps a map of which domain transaltes to what theme.

public class DomainNameThemeResolver extends AbstractThemeResolver {

  private Map domainNameThemeMap = new HashMap();

  
  public String resolveThemeName(HttpServletRequest request) {
    String xFwdFor = request.getHeader("x-forwarded-for");

    if(xFwdFor == null) {
      return getDefaultThemeName();
    }

    String themeName = domainNameThemeMap.get(xFwdFor.trim().toLowerCase());
    if(StringUtils.isBlank(themeName)) themeName = getDefaultThemeName();

    return themeName;

  }

  
  public void setThemeName(HttpServletRequest request, HttpServletResponse response, String themeName) {

  }

  public Map getDomainNameThemeMap() {
    return domainNameThemeMap;
  }

  public void setDomainNameThemeMap(Map domainNameThemeMap) {
    this.domainNameThemeMap = domainNameThemeMap;
  }

}

And finally, back to the WebMvcConfigurerAdapter, I also need to register this ThemeResolver bean


public ThemeResolver themeResolver() {
  DomainNameThemeResolver themeResolver = new DomainNameThemeResolver();
  themeResolver.setDefaultThemeName("firstdomain");
  themeResolver.getDomainNameThemeMap().put("myapp.firstdomain.com", "firstdomain");
  themeResolver.getDomainNameThemeMap().put("myapp.seconddomain.com", "seconddomain");
  return themeResolver;
}

The theme-specific key value pairs can then be obtained on the thymeleaf view using the special #themes.code(...) syntax. Here’s an example:

  

Enjoy!

Leave a Reply