[Freemarker] No TLD was found for the "http://tiles.apache.org/tags-tiles" JSP taglib URI 오류 조치
Freemarker를 사용하며 tiles 및 spring과 같이 taglib가 필요한 경우가 있다. 그냥 Jsp에서 사용하던대로
<%@taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles"%>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
이런식으로 url을 매핑하여 작성하면
<#assign tiles=JspTaglibs["http://tiles.apache.org/tags-tiles"]>
<#assign spring=JspTaglibs["http://www.springframework.org/tags"]>
이렇게 ftl 파일에서 taglib를 사용하기 위해 다음과 같이 작성을 하였는데 다음과 같은 오류가 발생하였다.
FreeMarker template error (HTML_DEBUG mode; use RETHROW in production!)
Error while looking for TLD file for "http://tiles.apache.org/tags-tiles"; see cause exception.
----
FTL stack trace ("~" means nesting-related):
- Failed at: #assign tiles = JspTaglibs["http://ti... [in template "WEB-INF/freemarker/auigrid/layout/main.ftl" at line 1, column 1]
----
Java stack trace (for programmers):
----
freemarker.template.TemplateModelException: [... Exception message was already printed; see it above ...]
at freemarker.ext.jsp.TaglibFactory.get(TaglibFactory.java:249)
... 중략 ...
Caused by: freemarker.ext.jsp.TaglibFactory$TaglibGettingException: No TLD was found for the "http://tiles.apache.org/tags-tiles" 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.)
at freemarker.ext.jsp.TaglibFactory.get(TaglibFactory.java:223)
No TLD was found 이게 오류의 핵심이다.
tld 파일을 못찾는다는건데 시도해본 방법중 되는건 다음 두가지이다.
(참고로 필자는 freemarker와 tiles를 같이 사용중이다. 만드는 샘플은 여기를 눌러보자. )
방안 1. tld 파일을 위치시키는 방법
위의 그림과 같이 resources/META-INF/tld 폴더를 만들고 필요한 tld 파일을 이곳으로 가지고 온다. tld 파일을 가지고 오는 요령은 예를들면 tiles-jsp.tld를 가지고 오고 싶다 하면 다음과 같이 tiles-jsp.jar 에서 가지고 올 수 있다.
마찬가지로 spring.tld도 spring-webmvc.jar에서 가지고 올 수 있다.
이 위치에 필요한 tld 파일을 가지고 오면 taglib을 사용할 수 있게 된다. 하지만 jar 안에도 엄연히 존재하는 tld를 꺼내와서 직접 참조 시키는 방안은 적절하지 않다고 본다.
방안 2. FreemarkerRendererBuilder 를 이용하는 방법
필자는 freemarker를 tiles와 같이 쓰다보니 여러가지 문제가 발생하였고 이를 해결하기 위한 방법중 하나가 TilesConfigurer 정의시에 tiles가 init 되는 시점에 필요한 정보를 집어넣는 것이었다.
@Bean
public TilesConfigurer tilesConfigurer() {
TilesConfigurer tilesConfigurer = new TilesConfigurer();
tilesConfigurer.setCompleteAutoload(true);
tilesConfigurer.setDefinitions("classpath*:/META-INF/resources/freemarker/layout-definition/tiles-layout.xml");
tilesConfigurer.setTilesInitializer(new CompleteAutoloadTilesInitializer() {
@Override
protected AbstractTilesContainerFactory createContainerFactory(ApplicationContext context) {
return new CompleteAutoloadTilesContainerFactory() {
@Override
protected void registerAttributeRenderers(BasicRendererFactory rendererFactory, ApplicationContext applicationContext, TilesContainer container, AttributeEvaluatorFactory attributeEvaluatorFactory) {
super.registerAttributeRenderers(rendererFactory, applicationContext, container, attributeEvaluatorFactory);
FreemarkerRendererBuilder freemarkerRenderer = FreemarkerRendererBuilder.createInstance();
freemarkerRenderer.setApplicationContext(applicationContext);
freemarkerRenderer.setParameter("ContentType", "text/html;charset=UTF-8");
freemarkerRenderer.setParameter("default_encoding", "UTF-8");
freemarkerRenderer.setParameter("ClasspathTlds", "/META-INF/tld/tiles-jsp.tld, /META-INF/spring.tld");
rendererFactory.registerRenderer("freemarker", freemarkerRenderer.build());
}
};
}
});
return tilesConfigurer;
}
init 되는 시점에 FreemarkerRendererBuilder를 통해 여러가지 정보를 넣을 수 있고 그중 17번째 라인을 보면 ClasspathTlds 라는 param을 통해 각 jar안에 있는 tld 파일들을 명시할 수 있다. 복수의 tld면 , 로 구분해서 하나의 String으로 넣어주면 된다. 이렇게 하면 방안 1과 같이 직접 tld 파일들을 관리하지 않고 jar안에 있는 tld를 이용할 수 있다.
끝!