I have my main layouts in /src/main/webapp/WEB-INF/layouts/layouts.xml
with sample entries like:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN"
"http://tiles.apache.org/dtds/tiles-config_2_1.dtd">
<tiles-definitions>
<definition name="default" template="/WEB-INF/layouts/default.jspx">
<put-attribute name="menu" value="/WEB-INF/views/menu.jspx"/>
<put-attribute name="sidebar" value="/WEB-INF/views/sidebar.jspx"/>
<put-attribute name="header" value="/WEB-INF/views/header.jspx" />
<put-attribute name="footer" value="/WEB-INF/views/footer.jspx" />
</definition>
<definition name="public" template="/WEB-INF/layouts/default.jspx">
<put-attribute name="menu" value="/WEB-INF/views/menu.jspx"/>
<put-attribute name="sidebar" value="/WEB-INF/views/sidebar.jspx"/>
<put-attribute name="header" value="/WEB-INF/views/header.jspx" />
<put-attribute name="footer" value="/WEB-INF/views/footer.jspx" />
</definition>
</tiles-definitions>
And then more specific tiles definitions in /src/main/webapp/WEB-INF/views/views.xml
with sample entries like:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN" "http://tiles.apache.org/dtds/tiles-config_2_1.dtd">
<tiles-definitions>
<definition extends="default" name="index">
<put-attribute name="body" value="/WEB-INF/views/index.jspx"/>
</definition>
<definition extends="public" name="login">
<put-attribute name="sidebar" value=""></put-attribute>
<put-attribute name="body" value="/WEB-INF/views/login.jspx"/>
</definition>
</tiles-definitions>
Then you need your configuration class:
@EnableWebMvc
@Configuration
public class RootMvcConfiguration extends WebMvcConfigurerAdapter {
...
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/login").setViewName("login");
}
...
}
Beans in that class that relate to tiles depend - if you want to use JSPs or Thymeleaf.
For JSP, you should have there:
@Bean
public UrlBasedViewResolver tilesViewResolver(){
UrlBasedViewResolver tilesViewResolver = new UrlBasedViewResolver();
tilesViewResolver.setViewClass(TilesView.class);
return tilesViewResolver;
}
@Bean
public TilesConfigurer tilesConfigurer(){
String[] definitions = new String[] {
"/WEB-INF/layouts/layouts.xml",
"/WEB-INF/views/**/views.xml" /*Scans directories for Tiles configurations */
};
TilesConfigurer tilesConfigurer = new TilesConfigurer();
tilesConfigurer.setDefinitions(definitions);
return tilesConfigurer;
}
If you use Thymeleaf you should have something like that:
@Bean
public MessageSource messageSource(){
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasenames("classpath:META-INF/i18n/messages");
messageSource.setFallbackToSystemLocale(false);
return messageSource;
}
@Bean
public ServletContextTemplateResolver templateResolver() {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
resolver.setPrefix("/WEB-INF/");
resolver.setSuffix(".html");
resolver.setTemplateMode("HTML5");
resolver.setOrder(2);
resolver.setCacheable(false);
return resolver;
}
@Bean
public SpringTemplateEngine templateEngine() throws Exception {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver());
engine.setTemplateEngineMessageSource(messageSource());
engine.addDialect(new TilesDialect());
engine.addDialect(new SpringSecurityDialect());
engine.afterPropertiesSet();
return engine;
}
@Bean
public TilesConfigurer tilesConfigurer(){
String[] definitions = new String[] {
"/WEB-INF/layouts/layouts.xml",
"/WEB-INF/views/**/views.xml" /*Scans directories for Tiles configurations */
};
ThymeleafTilesConfigurer tilesConfigurer = new ThymeleafTilesConfigurer();
tilesConfigurer.setDefinitions(definitions);
return tilesConfigurer;
}
Then you can extend your views.xml and point view names to your jsp or html files and an example controller can be as follows:
@RequestMapping("/roles")
@Controller
public class RoleController {
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public String show(@PathVariable("id") Integer id, Model uiModel) {
uiModel.addAttribute("role", Role.findRole(id));
uiModel.addAttribute("itemId", id);
return "roles/show";
}
}
If you use Maven, here are some sample lib versions:
<properties>
<thymeleaf.version>2.0.19</thymeleaf.version>
<thymeleaf.extras.version>2.0.0</thymeleaf.extras.version>
<thymeleaf.extras.security.version>2.0.0</thymeleaf.extras.security.version>
<tiles.version>2.2.2</tiles.version>
</properties>
...
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-core</artifactId>
<version>${tiles.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-jsp</artifactId>
<version>${tiles.version}</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>${thymeleaf.version}</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring3</artifactId>
<version>${thymeleaf.version}</version>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity3</artifactId>
<version>${thymeleaf.extras.security.version}</version>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-tiles2</artifactId>
<version>${thymeleaf.extras.version}</version>
</dependency>
WEB-INF
)? Maybe try setting theorder
on yourViewResolver
to something lower than the default (so there's no chance of a clash)? P.S. (not relevant to getting Tiles to work) you don't use theHttpServlet*
parameters in your controller, and it's bad style to require them, so you can just remove them. – VaticinalHttpServlet
parameters. I tried specifying@Order(value=Ordered.LOWEST_PRECEDENCE-100)
on the view resolver...same issue still exists – Leprechaun