Java OSGi中的Velocity:如何从类路径加载模板
我正在使用velocity模板引擎为OSGi开发一个应用程序。 通过文件加载器加载模板非常有效,但现在我必须在jar中实现这些模板,并将其作为资源加载 我怎样才能让它工作 我的代码:Java OSGi中的Velocity:如何从类路径加载模板,java,osgi,velocity,Java,Osgi,Velocity,我正在使用velocity模板引擎为OSGi开发一个应用程序。 通过文件加载器加载模板非常有效,但现在我必须在jar中实现这些模板,并将其作为资源加载 我怎样才能让它工作 我的代码: ve = new VelocityEngine(); ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); ve.setProperty("classpath.resource.loader.class", ClasspathReso
ve = new VelocityEngine();
ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
ve.setProperty("classpath.resource.loader.class",
ClasspathResourceLoader.class.getName());
ve.setProperty("classpath.resource.loader.path", "/velocitytemplates");
ve.init();
ve.getTemplate("foo.vm");
这将抛出一个异常,如
找不到资源“index.vm”
原因:
org.apache.velocity.exception.ResourceNotFoundException:找不到资源“index.vm”
有两件事需要核实
1.类路径问题
确保通过MANIFEST.MF将OSGi捆绑包的类路径设置为包含一个点:
Bundle-ClassPath: .
点表示在类加载层次结构中包含包的根,文件夹“velocitytemplates”可能位于该层次结构中
您需要将Velocity jar文件放在模板文件所在的同一个捆绑包中,因为否则您会遇到类加载问题,因为Velocity将位于不同的捆绑包中,因此在其类路径中根本看不到“velocitytemplates”
2.ClasspathResourceLoader没有“路径”
ClasspathResourceLoader不支持设置“路径”,因为它根据定义使用类路径,因此可以将“velocitytemplates”添加到OSGi捆绑包(MANIFESt.MF)中的类路径中,或者使用完整路径引用velocity模板,即“velocitytemplates/index.vm”我在基于类加载器的模板中遇到了类似的问题,我想指定一个不同的根。我通过子类化ClasspathResourceLoader解决了这个问题
package my.package;
import java.io.InputStream;
import org.apache.commons.collections.ExtendedProperties;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
public class PrefixedClasspathResourceLoader
extends ClasspathResourceLoader
{
/** Prefix to be added to any names */
private String prefix = "";
@Override
public void init(ExtendedProperties configuration) {
prefix = configuration.getString("prefix","");
}
@Override
public InputStream getResourceStream(String name)
throws ResourceNotFoundException
{
return super.getResourceStream(prefix+name);
}
}
设置了以下属性
resource.loader=myloader
myloader.resource.loader.class=my.package.PrefixedClasspathResourceLoader
myloader.resource.loader.prefix=/velocitytemplates/
这样,如果您有一个名为“index.vm”的模板,velocity将使用类加载器查找名为“/velocitytemplates/index.vm”的资源。遗憾的是,velocity对OSGi并不友好。因此,您不能使用内置的ClasspathResourceLoader,也很难添加自定义开发的ResourceLoader 我建议您以任何普通方式获取模板作为读者,并选择以下方式之一:
- 如果需要合并,请使用VelocityEngine evaulate函数 模板很少(性能没有那么重要)
- 使用Velocity的内部类手动创建模板
请注意,该示例遗漏了一些try-catch-finally块。两天后,我和一位同事找到了Velocity引擎的默认解决方案:file.resource.loader.class=org.apache.Velocity.runtime.resource.loader.FileResourceLoader 像这样创建了自己的类资源加载器
public static final class PdfResourceLoader extends ResourceLoader
@Override
public void init(ExtendedProperties configuration)
{
}
@Override
public InputStream getResourceStream(String source) throws ResourceNotFoundException
{
return getClass().getResourceAsStream(source);
}
@Override
public boolean isSourceModified(Resource resource)
{
return false;
}
@Override
public long getLastModified(Resource resource)
{
return 0;
}
}
设置新的上下文类加载器
Thread.currentThread().setContextClassLoader(PdfResourceLoader.class.getClassLoader());
VelocityEngine ve = new VelocityEngine();
更改了velocity引擎内部的默认属性
ve.setProperty("resource.loader", "pdf");
ve.setProperty("pdf.resource.loader.class",
PdfResourceLoader.class.getName());
ve.init();
示例名称路径模板
String pathTemplate = "/templates/yourTemplateName.html";
Template t = ve.getTemplate(pathTemplate, "UTF-8");
如果资源在您的捆绑包中,那么Velocity需要使用捆绑包的类加载器来加载它们。Velocity可能正在使用自己的类加载器,因此无法查看捆绑包中的资源。您需要找到一种方法来配置
ClasspathResourceLoader
来告诉它要使用哪个类加载器,否则您需要使用其他类型的资源加载策略。不幸的是,我对Velocity了解不够,无法提供更具体的建议。我没有使用OSGi,但我们有一种自己开发的东西,让人想起它与多个类加载器的关系——我们也遇到了同样的问题。你的第二种方法,手工创建模板,成功了!但是,如果下载程序在外部软件包中,velocity如何找到它呢?如果我这样做,只要编译的文件包含在类路径中,velocity就不会找到类PrefixedClasspathResourceLoader
@iberbeu,那么velocity应该能够通过名称找到它。在我的例子中,我只是在调用Velocitybut的应用程序中包含了类加载器,但在OSGI中它必须包含在velocity包的类路径中。那么,如何让velocity在类加载器所在的位置导入这个包呢?我不是OSGI专家,所以帮不上什么忙。除非您可以将Velocity捆绑包替换为您自己构建的包含Velocity和自定义加载程序的捆绑包。如果您准备让该类可用于所有捆绑包,那么快速谷歌搜索可能会很有用。
String pathTemplate = "/templates/yourTemplateName.html";
Template t = ve.getTemplate(pathTemplate, "UTF-8");