На самом деле это простая задача, если вы знаете, как это делать. Все, что вам нужно, уже встроено в FreeMarker, например это TaglibFactory.ClasspathMetaInfTldSource
класс. Я потратил несколько часов на изучение этой проблемы, поэтому хочу поделиться решением.
Я реализовал его как BeanPostProcessor
, потому что теперь нет возможности установить TaglibFactory
до инициализации FreeMarkerConfigurer
bean-компонента.
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;
}
}
Единственное ограничение - файлы *.tld
должны иметь внутри тег <uri>
xml. Он есть во всех стандартных TLD с пружинной / пружинной защитой. А также эти файлы должны находиться внутри META-INF
папки пути к классам, например META-INF/mytaglib.tld
. Все стандартные TLD с пружинной / пружинной защитой также следуют этому соглашению.
Прокомментированная строка - это всего лишь пример того, как вы можете добавить «пользовательские» пути к *.tld
файлам, если по какой-то причине вы не можете разместить их в стандартном месте (возможно, какой-то внешний jar, который не соответствует соглашению). Его можно расширить до некоторого вида сканирования пути к классам, поиска всех *.tld
файлов и добавления их в classpathTlds
. Но обычно это не требуется, если ваши TLD следуют соглашениям JSP и помещаются в каталог META-INF
.
Я протестировал это в моем шаблоне FreeMarker, и он работает:
<#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"]>
Для настраиваемого тега ("http://my-custom-tag-library/tags") для работы это должен быть *.tld
файл в src/main/resources/META-INF/some.tld
и должен содержать тег <uri>
xml, например <uri>http://my-custom-tag-library/tags</uri>
. Тогда он будет найден FreeMarker.
Надеюсь, это поможет кому-то сэкономить несколько часов, чтобы найти «правильное» решение этой проблемы.
Протестировано с помощью spring -boot v2.0.5.RELEASE
person
Ruslan Stelmachenko
schedule
20.02.2019