I was using JSP + JSTL but I'm boring of c:if, c:choose, ...
So, I want my JSP pages to be rendered with both JSP and Thymeleaf (I plan to remove all JSTL as soon as possible). I am using the Spring MVC framework:
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/" />
<property name="suffix" value=".jsp" />
<property name="order" value="1" />
</bean>
<!-- Thymeleaf -->
<bean id="templateResolver" class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
<property name="prefix" value="/WEB-INF/pages/" />
<property name="suffix" value=".html" />
<property name="templateMode" value="HTML5" />
</bean>
<bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver" />
</bean>
<bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine" />
<property name="order" value="2" />
</bean>
In my controller, I just return the jsp without extenion.
return "folder/page";
Can my JSP pages be renderd first with the JSP resolver and then with the Thymeleaf resolver? If yes, how?
It seems that it is very complicated to chain JSP and Thymeleaf. So, I want to use the Internal resolver for JSP files and Thymeleaf template resolver for HTML files. How can I do it?
According to this post on the Thymeleaf forum, you have two solutions.
First solution :
Remove the suffix property in your bean declaration (<property name="suffix" value=".html" />
and <property name="suffix" value=".jsp" />
) and pass the suffix in the return value of your controllers, e.g. :
@RequestMapping("/view1")
public String thymeleafView(){
return "mythymeleafview.html";
}
@RequestMapping("/view2")
public String jspView(){
return "myjspview.html";
}
Second solution :
Add the viewNames
property to the resolvers. The value is the name of a folder which contains views depending on their extension. So you will have one folder for JSP files and another for HTML (thymeleaf) files, e.g. :
Configuration
<bean id="templateResolver" class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".html" />
<property name="viewNames" value="thymeleaf/*" />
<property name="templateMode" value="HTML5" />
</bean>
<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/views/" />
<property name="viewNames" value="jsp/*" />
<property name="suffix" value=".jsp" />
</bean>
Controller
@RequestMapping("/view1")
public String thymeleafView() {
return "thymeleaf/mythymeleafview";
}
@RequestMapping("/view2")
public String jspView() {
return "jsp/myjspview";
}
Project folder
WEB-INF/views/jsp/myjspview.jsp
WEB-INF/views/thymeleaf/mythymeleafview.jsp
Both solutions work but have some contraints. You have to specify one way or another whether you want to resolve with JSP or Thymeleaf.
The "perfect" solution to chain JSP and Thymeleaf — which would consist in trying to resolve the view with JSP when it cannot be resolved with Thymeleaf or vice versa — is not possible, and Daniel Fernández (Thymeleaf team) explained why in this same post :
Thymeleaf allows you to create whichever ITemplateResolver implementation you wish, including some that might not allow to determine whether the template exists or not before actually reading it. [...] So, there is no way for Thymeleaf to be sure whether a template will be resolvable or not before trying to process the template. And that's why the ThymeleafViewResolver has to resort to the "viewNames" property.