Spring boot 在嵌入式Tomcat中使用JSP标记Libs进行Spring引导
我目前正在迁移一个SpringMVCwebapp(通过SpringBoot将xml配置迁移到java配置,将tomcat迁移到嵌入式tomcat) webapp使用freemarker作为模板引擎和JSP标记库。现在,当我调用freemarker页面时,会出现以下错误:Spring boot 在嵌入式Tomcat中使用JSP标记Libs进行Spring引导,spring-boot,freemarker,jsp-tags,embedded-tomcat-8,Spring Boot,Freemarker,Jsp Tags,Embedded Tomcat 8,我目前正在迁移一个SpringMVCwebapp(通过SpringBoot将xml配置迁移到java配置,将tomcat迁移到嵌入式tomcat) webapp使用freemarker作为模板引擎和JSP标记库。现在,当我调用freemarker页面时,会出现以下错误: freemarker.ext.jsp.TaglibFactory$TaglibGettingException: No TLD was found for the "http://www.springframework.org
freemarker.ext.jsp.TaglibFactory$TaglibGettingException:
No TLD was found for the "http://www.springframework.org/tags/form" JSP taglib URI. (TLD-s are searched according the JSP 2.2 specification. In development- and embedded-servlet-container setups you may also need the "MetaInfTldSources" and "ClasspathTlds" freemarker.ext.servlet.FreemarkerServlet init-params or the similar system properites.)
freemarker-header.ftl以以下代码段开头:
<#assign form=JspTaglibs["http://www.springframework.org/tags/form"]>
<#assign core=JspTaglibs["http://java.sun.com/jstl/core"]>
<#assign spring=JspTaglibs["http://www.springframework.org/tags"]>
<#assign osc=JspTaglibs["/WEB-INF/osc.tld"]>
我没有找到MetaInfTldSources和ClassPathTLD的任何可用搜索结果。以前有人解决过这个问题吗
韩元
HabibSpring Boot不支持使用带有现成Freemarker的JSP标记库。有一个你可能感兴趣的问题。它包含一个指向可能的解决方案的链接,在该解决方案中,您可以配置
freemarkerconfiguer
的标记库工厂,并从类路径加载一些额外的TLD:
freeMarkerConfigurer.getTaglibFactory().setClasspathTlds(…);
这真的应该是内置的 首先,在
应用程序上禁用内置的freemakerautoconfiguration
:
@SpringBootApplication
@EnableAutoConfiguration(exclude = {FreeMarkerAutoConfiguration.class})
public class Application extends WebMvcConfigurerAdapter {
...
]
然后添加此自定义配置:
(改编自;向TaglibFactory
添加了ObjectWrapper
,并删除了addResourceHandlers()
覆盖)
然后,您可以在模板中加载:
<#assign s=JspTaglibs["/META-INF/spring.tld"] />
<a href="${s.mvcUrl("IC#index").build()}">Home</a>
在呈现模板时,freemarker调用TaglibFactory,它通过四种方式搜索TLD:
addTldLocationsFromClasspathTlds
addTldLocationsFromWebXml
addtldLocationsfromebinftlds
addTldLocationsFromMetaInfTlds
所有这些方法都在freemarker jar的TablibFactory类中。最后,扫描WEB-INF/lib中的每个jar,搜索/META-INF/***.tld。如果启用freemarker的调试模式,则可以看到此日志记录
看看您的项目是如何部署的。在我的例子中,使用eclipse、wtp、tomcat和maven,maven依赖项在eclipse/Deployment assembly中配置为maven依赖项,当然:),因此这些lib不在WEB-INF/lib中,因此,addtllocationsfrommetainftld
找不到
一种解决方法是强制部署将所有maven依赖项复制到WEB-INF/lib。我在eclipse的“服务器”视图中打开了服务器配置,在“服务器选项”下取消选中所有复选框,但“默认情况下自动重新加载模块”。如果您知道如何操作,这实际上是一项简单的任务。您所需要的一切都已经嵌入到FreeMarker中,例如它是TaglibFactory.ClasspathMetaInfTldSource
class。我花了几个小时调查这个问题,所以我想分享一个解决方案
我将其实现为BeanPostProcessor
,因为在FreeMarkerConfigure
bean初始化之前,现在无法设置TaglibFactory
import freemarker.ext.jsp.TaglibFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import java.util.Arrays;
import java.util.regex.Pattern;
/**
* A {@link BeanPostProcessor} that enhances {@link FreeMarkerConfigurer} bean, adding
* {@link freemarker.ext.jsp.TaglibFactory.ClasspathMetaInfTldSource} to {@code metaInfTldSources}
* of {@link TaglibFactory}, containing in corresponding {@link FreeMarkerConfigurer} bean.
*
* <p>
* This allows JSP Taglibs ({@code *.tld} files) to be found in classpath ({@code /META-INF/*.tld}) in opposition
* to default FreeMarker behaviour, where it searches them only in ServletContext, which doesn't work
* when we run in embedded servlet container like {@code tomcat-embed}.
*
* @author Ruslan Stelmachenko
* @since 20.02.2019
*/
@Component
public class JspTagLibsFreeMarkerConfigurerBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof FreeMarkerConfigurer) {
FreeMarkerConfigurer freeMarkerConfigurer = (FreeMarkerConfigurer) bean;
TaglibFactory taglibFactory = freeMarkerConfigurer.getTaglibFactory();
TaglibFactory.ClasspathMetaInfTldSource classpathMetaInfTldSource =
new TaglibFactory.ClasspathMetaInfTldSource(Pattern.compile(".*"));
taglibFactory.setMetaInfTldSources(Arrays.asList(classpathMetaInfTldSource));
// taglibFactory.setClasspathTlds(Arrays.asList("/META-INF/tld/common.tld"));
}
return bean;
}
}
要使自定义标记(“”)起作用,它必须是src/main/resources/META-INF/some.tld中的*.tld
文件,并且必须包含
xml标记,如http://my-custom-tag-library/tags
。它将由FreeMarker找到
我希望它能帮助人们节省几个小时来找到这个问题的“正确”解决方案
使用spring boot v2.0.5进行测试。发布版这些解决方案对我都不起作用,但在分析中的解决方法后,我找到了一个确实有效的解决方案:
1-在pom.xml中添加以下内容
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
</dependency>
3-现在您可以加载ftl文件,例如安全LIB
<#assign spring = JspTaglibs["http://www.springframework.org/security/tags"]>
我希望这对其他人有用 嗨,我试过了,但没用。。。当前的解决方法是将TLD从JAR放入webapp/META-INF文件夹。但这仅在使用springboot:run命令启动应用程序时有效。通过IntelliJ中的标准主应用程序类运行应用程序会导致相同的结果,即应用程序找不到tld文件…:-(回答得很好,完全解决了这个问题。我个人正试图将spring安全支持添加到我的freemarker文件中,在添加这个CustomFreeMarker配置之后,我所要做的就是完成这项工作。
<#assign common = JspTaglibs["http://my-custom-tag-library/tags"]>
<#assign security = JspTaglibs["http://www.springframework.org/security/tags"]>
<#assign form = JspTaglibs["http://www.springframework.org/tags/form"]>
<#assign spring = JspTaglibs["http://www.springframework.org/tags"]>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
</dependency>
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.List;
public class ClassPathTldsLoader {
private static final String SECURITY_TLD = "/META-INF/security.tld";
final private List<String> classPathTlds;
public ClassPathTldsLoader(String... classPathTlds) {
super();
if(ArrayUtils.isEmpty(classPathTlds)){
this.classPathTlds = Arrays.asList(SECURITY_TLD);
}else{
this.classPathTlds = Arrays.asList(classPathTlds);
}
}
@Autowired
private FreeMarkerConfigurer freeMarkerConfigurer;
@PostConstruct
public void loadClassPathTlds() {
freeMarkerConfigurer.getTaglibFactory().setClasspathTlds(classPathTlds);
}
}
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FreemarkerTaglibsConfig {
@Bean
@ConditionalOnMissingBean(ClassPathTldsLoader.class)
public ClassPathTldsLoader classPathTldsLoader(){
return new ClassPathTldsLoader();
}
}
<#assign spring = JspTaglibs["http://www.springframework.org/security/tags"]>