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!