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 MapdomainNameThemeMap = 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!