Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using both Thymeleaf and JSP

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?

like image 960
Athanor Avatar asked Feb 12 '15 14:02

Athanor


People also ask

What is the difference between JSP and thymeleaf?

Both JSP and Thymeleaf use tags, but each tag is specific to the its implementation. - As you can see Thymeleaf is closer to the HTML format and for this reason Thymeleaf is named " a natural template " - JSP is the old fashion of creating the View into a MVC application

What is thymeleaf template?

Thymeleaf templates are intended to be natural – as close to straight HTML as possible, and easily interpreted by browsers and developers alike. Thymeleaf is packed with several dialects, and takes the place of JSP in the default stack provided by Spring.

How does thymeleaf work with static pages?

The template file statically links to the CSS in its tag (with an href that Thymeleaf substitutes when executing the template by the one generated by th:href). So any changes we make to that CSS will be applied to the static page our browser is displaying.

Is it possible to have prototype code in thymeleaf?

We are allowed to have prototype code there: for example, we can set an Email: text in the label for the first field, knowing that Thymeleaf will substitute it with the internationalized text with key subscription.email when it executes the page. We have even been able to add an <li> for a second radiobutton just for prototyping pleasure.


4 Answers

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.

like image 140
lgd Avatar answered Oct 08 '22 06:10

lgd


Alternatively, two servlets works fine. The key is to keep servlet configuration minimal and include an appConfig.xml for database and other services (this avoids massive duplication of configuration)

Web.xml:

<web-app id="WebApp_ID" version="2.4"
   xmlns="http://java.sun.com/xml/ns/j2ee" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

   <display-name>Spring MVC Application</display-name>

   <servlet>
      <servlet-name>AssessmentAdmin</servlet-name>
      <servlet-class>
         org.springframework.web.servlet.DispatcherServlet
      </servlet-class>
      <load-on-startup>1</load-on-startup>
   </servlet>
 <servlet-mapping>
      <servlet-name>AssessmentAdmin</servlet-name>
      <url-pattern>/xz/*</url-pattern>
   </servlet-mapping>
   
   
<servlet>
      <servlet-name>AssessmentAdminTL</servlet-name>
      <servlet-class>
         org.springframework.web.servlet.DispatcherServlet
      </servlet-class>
      <load-on-startup>1</load-on-startup>
   </servlet>   
   <servlet-mapping>
      <servlet-name>AssessmentAdminTL</servlet-name>
      <url-pattern>/xztl/*</url-pattern>
   </servlet-mapping>
   ........

servlet for jsp:

<mvc:annotation-driven />
	
	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/jsp/" />
		 <!--  <property name="viewNames" value="jsp/*" />-->
		  <property name="suffix" value=".jsp" />
	</bean>



	..........



	
	<import resource="applicationContext.xml" />



</beans>

servlet for thymeleaf

<mvc:annotation-driven />
	
<!-- Thymeleaf -->

<bean id="templateResolver"
        class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
    <property name="prefix" value="/WEB-INF/html/" />
    <property name="suffix" value=".html" />
    <property name="templateMode" value="HTML5" />
    <property name="cacheable" value="false" />
  </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" />
  </bean> 
    
 
   
  <bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
    <property name="templateEngine" ref="templateEngine" />
  </bean> 	
  
  


	
	<import resource="applicationContext.xml" />

Tried it and it works fine

like image 24
Jake Avatar answered Oct 08 '22 05:10

Jake


Here is the answer based on @Igd response

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/pages/" />
    <property name="viewNames" value="*.jsp" />
</bean>
<!-- Thymeleaf -->
<bean id="templateResolver" class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
    <property name="prefix" value="/WEB-INF/pages/" />
    <property name="templateMode" value="HTML5" />
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewNames" value="redirect*" />
</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="viewNames" value="*.html" />
</bean> 

And i use this for the mapping:

@RequestMapping("/view1")
public String thymeleafView(){
    return "mythymeleafview.html";
}

@RequestMapping("/view2")
public String jspView(){
    return "myjspview.jsp";
}
like image 36
Athanor Avatar answered Oct 08 '22 07:10

Athanor


according to @Athanor's answer,we may have another choice.

we use property "viewNames" to control which resolver the template select

<!-- jsp -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/" />
    <property name="suffix" value=".jsp" />
    <property name="order" value="1" />
    <property name="viewNames" value="*admin/*,*packer/*,*courier/*,/" />
</bean>
<!-- thymeleaf -->
<bean id="templateResolver" class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
    <property name="prefix" value="/" />
    <property name="suffix" value=".html" />
    <property name="templateMode" value="HTML5" />
    <property name="cacheable" value="false"/>
</bean>
<bean id="templateEngine" class="org.thymeleaf.spring3.SpringTemplateEngine">
    <property name="templateResolver" ref="templateResolver" />
</bean>
<bean class="org.thymeleaf.spring3.view.ThymeleafViewResolver">
    <property name="characterEncoding" value="UTF-8"/>
    <property name="templateEngine" ref="templateEngine" />
    <property name="viewNames" value="*thymeleaf/*" />
    <property name="order" value="2" />
</bean>

and the controller

@RequestMapping(value="/test")
public ModelAndView dboxPrint(Model model){
    ModelAndView modelAndView = new ModelAndView("thymeleaf/dbox_print");

    return modelAndView;
}
like image 1
user5606857 Avatar answered Oct 08 '22 06:10

user5606857