同时使用 Thymeleaf 和 JSP
Posted
技术标签:
【中文标题】同时使用 Thymeleaf 和 JSP【英文标题】:Using both Thymeleaf and JSP 【发布时间】:2015-04-13 08:25:45 【问题描述】:我使用的是 JSP + JSTL,但我对 c:if、c:choose 感到厌烦...
所以,我希望我的 JSP 页面同时使用 JSP 和 Thymeleaf 呈现(我计划尽快删除所有 JSTL)。我正在使用 Spring MVC 框架:
<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>
在我的控制器中,我只返回不带扩展名的 jsp。
return "folder/page";
可以先用 JSP 解析器再用 Thymeleaf 解析器渲染我的 JSP 页面吗?如果是,怎么做?
JSP 和 Thymeleaf 的链接似乎很复杂。所以,我想对 JSP 文件使用内部解析器,对 HTML 文件使用 Thymeleaf 模板解析器。我该怎么做?
【问题讨论】:
对您的想法的一些想法:您可以提供自己的 ViewResolver 来检测ServletContextTemplateResolver
和 InternalResourceViewResolver
,但它会同时处理这两者,这可能会导致繁重的 WTF 场景。就像评论一样,因为我没有看到任何解决方案可以同时处理两者。
我了解如何将 JSP 用于 *.jsp 文件,将 Thymeleaf 用于 *.html 文件?我必须更改控制器中的内容吗?
如果我理解正确,您现在“只是”想根据返回的视图进行切换?所以没有混合视图处理。您可以通过将 Thymeleaf ViewResolver 的文件名后缀更改为 html 来尝试。它可能毫无例外地通过 InternalViewResolver 并触发 templateResolver。因此,您只需将新模板重命名为 *.html。我这里没有代码和库来测试这个想法。
如果不可能或真的很痛苦,我需要找到另一种解决方案。所以我现在想为 HTML 模板文件添加 Thymeleaf。我会保留 JSP 支持,因为我需要时间来重写它们。
【参考方案1】:
根据 Thymeleaf 论坛上的this post,您有两种解决方案。
第一个解决方案:
删除 bean 声明(<property name="suffix" value=".html" />
和 <property name="suffix" value=".jsp" />
)中的后缀属性,并在控制器的返回值中传递后缀,例如:
@RequestMapping("/view1")
public String thymeleafView()
return "mythymeleafview.html";
@RequestMapping("/view2")
public String jspView()
return "myjspview.html";
第二种解决方案:
将viewNames
属性添加到解析器。该值是包含视图的文件夹的名称,具体取决于视图的扩展名。因此,您将有一个文件夹用于 JSP 文件,另一个文件夹用于 HTML (thymeleaf) 文件,例如:
配置
<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>
控制器
@RequestMapping("/view1")
public String thymeleafView()
return "thymeleaf/mythymeleafview";
@RequestMapping("/view2")
public String jspView()
return "jsp/myjspview";
项目文件夹
WEB-INF/views/jsp/myjspview.jsp
WEB-INF/views/thymeleaf/mythymeleafview.jsp
两种解决方案都有效,但有一些限制。无论您想使用 JSP 还是 Thymeleaf 解析,您都必须指定一种或另一种方式。
链接 JSP 和 Thymeleaf 的“完美”解决方案——包括在无法用 Thymeleaf 解决视图时尝试用 JSP 解决视图,或者反之亦然——是不可能的,Daniel Fernández (Thymeleaf 团队)在this same post 中解释了原因:
Thymeleaf 允许您创建任何您希望的 ITemplateResolver 实现,包括一些在实际阅读模板之前可能不允许确定模板是否存在的实现。 [...] 因此,Thymeleaf 在尝试处理模板之前无法确定模板是否可解析。这就是 ThymeleafViewResolver 必须求助于“viewNames”属性的原因。
【讨论】:
【参考方案2】:另外,两个 servlet 也可以正常工作。关键是尽量减少 servlet 配置,并包含一个 appConfig.xml 用于数据库和其他服务(这样可以避免大量重复配置)
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>
........
jsp 的 servlet:
<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
<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" />
试过了,效果很好
【讨论】:
【参考方案3】:这是基于@Igd 响应的答案
<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>
我将它用于映射:
@RequestMapping("/view1")
public String thymeleafView()
return "mythymeleafview.html";
@RequestMapping("/view2")
public String jspView()
return "myjspview.jsp";
【讨论】:
【参考方案4】:根据@Athanor 的回答,我们可能有另一种选择。
我们使用属性“viewNames”来控制模板选择哪个解析器
<!-- 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>
和控制器
@RequestMapping(value="/test")
public ModelAndView dboxPrint(Model model)
ModelAndView modelAndView = new ModelAndView("thymeleaf/dbox_print");
return modelAndView;
【讨论】:
以上是关于同时使用 Thymeleaf 和 JSP的主要内容,如果未能解决你的问题,请参考以下文章
Spring MVC、Tiles2、ThymeLeaf 和自然模板
Spring Boot、Spring Security 和 Thymeleaf:将 CsrfFilter 应用到带有表单的网站