This is the sort of weird question one runs into when shamelessly copying examples from the Internet. I am using Spring MVC 4, Apache Tiles 3, Java 8, and Tomcat 8.
I absolutely must have a views.properties file. BUT it doesn't need to have any actual mappings in it. So the question is not so much why do I need it, but why don't I need it.
As you can see from the views.properties file it has one entry that has nothing at all to do with userList. If the file is missing completely the DispatcherServlet throws an Exception. But with this pitiful entry everything works fine. Granted it does list the TilesView class, and supplies a somewhat general idea of where one might look for JSPs. But everything I've read says each JSP must be meticulously listed in the views.properties file. That simply isn't true.
On one hand this is good because it is a lot less to maintain. But on the other it makes me feel like I am really missing something important. Disclaimer: I haven't yet cracked the static resource resolver, which is proving quite recalcitrant. That seems completely unrelated to this, other than both being general issues with Spring finding my resources.
The infamous views.properties (ENTIRE FILE)
messages.(class)=org.springframework.web.servlet.view.tiles3.TilesView
messages.url=/WEB-INF/xxxx/messages.jsp (for example)
Obligatory code examples:
@Configuration Class
...
@Bean
TilesConfigurer tilesConfigurer() {
TilesConfigurer tilesConfigurer = new TilesConfigurer();
tilesConfigurer.setDefinitions("WEB-INF/tiles/tiles.xml");
return tilesConfigurer;
}
@Bean
ResourceBundleViewResolver viewResolver() {
ResourceBundleViewResolver resourceBundleViewResolver = new ResourceBundleViewResolver();
resourceBundleViewResolver.setBasename("views");
return resourceBundleViewResolver;
}
@Bean
TilesViewResolver tilesVewResolver() {
return new TilesViewResolver();
}
...
tiles.xml
<tiles-definitions>
<definition name="baseLayout" template="/WEB-INF/tiles/maintemplate.jspx">
<put-attribute name="header" value="/WEB-INF/tiles/header.jspx" />
<put-attribute name="menu" value="/WEB-INF/tiles/menu.jspx" />
<put-attribute name="body" value="" />
<put-attribute name="footer" value="/WEB-INF/tiles/footer.jspx" />
</definition>
<!-- USERS -->
<definition name="userEdit" extends="baseLayout">
<put-attribute name="title" value="Edit User" />
<put-attribute name="body" value="/WEB-INF/views/users/edit.jspx" />
</definition>
<definition name="userList" extends="baseLayout">
<put-attribute name="title" value="List Users" />
<put-attribute name="body" value="/WEB-INF/views/users/list.jspx" />
</definition>
...
UserController.java
...
@PreAuthorize("isAuthenticated()")
@RequestMapping(method = RequestMethod.GET)
public String list(Locale locale, HttpServletRequest request, HttpServletResponse response, Model uiModel) {
themeResolver.setThemeName(request, response, "defaultTheme");
List<User> users = userRepository.findAll();
uiModel.addAttribute("users", users);
return "userList";
}
...
The ResourceBundleViewResolver
requires an additional configuration file which contains a configuration for every view it can handle. By default the basename of views
is used. If this file isn't there the ResourceBundleViewResolver
will fail to load/start.
Judging by the behavior you describe and the fact that you use Tiles I suspect that you also have a TilesViewResolver
. For tiles the name of the view returned, here userList
, must correspond to a tiles view definition.
When using Spring MVC all configured ViewResolver
s are consulted to resolve the name of the view to an actual View
implementation. In your case the ResourceBundleViewResolver
will return null
for the view resolution as it can only handle a view named messages
, next the TilesViewResolver
is consulted which will return a view as there is a tiles view definition for userList
.