[英]Velocity in OSGi: how to load templates from classpath
I am developing an application for OSGi with velocity template engine. 我正在开发一个带速度模板引擎的OSGi应用程序。 It works great for loading my templates by file loader but now I have to implement this templates in my jar and load it as resources.
它适用于通过文件加载器加载我的模板,但现在我必须在我的jar中实现这个模板并将其作为资源加载。
How can i made it work? 我怎样才能使它发挥作用?
My Code: 我的代码:
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");
This will throw an exception like 这将抛出一个例外
Unable to find resource 'index.vm'
无法找到资源'index.vm'
Caused by:
引起:
org.apache.velocity.exception.ResourceNotFoundException: Unable to find resource 'index.vm'
org.apache.velocity.exception.ResourceNotFoundException:无法找到资源'index.vm'
Sadly Velocity is not that OSGi friendly. 可悲的是Velocity并不是OSGi友好的。 Therefore you cannot use the built in ClasspathResourceLoader and it is hard to add a custom developed ResourceLoader as well.
因此,您无法使用内置的ClasspathResourceLoader,也很难添加自定义开发的ResourceLoader。
I suggest that you should get your template as a Reader in any of the ordinary ways and choose one of the following: 我建议您以任何常规方式将模板作为Reader使用,并选择以下选项之一:
The first option can be used if you do not have to merge your templates very often so performance is not a key requirement. 如果您不必经常合并模板,则可以使用第一个选项,因此性能不是关键要求。
Here is a sample for the second option where the created template object can be reused by calling the merge function on it (expecting that you already got a Reader to your vm file or resource): 下面是第二个选项的示例,其中可以通过调用其上的合并函数来重用创建的模板对象(期望您已经有一个读取器到您的vm文件或资源):
RuntimeInstance runtimeInstance = new RuntimeInstance();
runtimeInstance.init();
SimpleNode simpleNode = runtimeInstance.parse(reader, "nameOfYourTemplateResource");
Template template = new Template();
simpleNode.init(new InternalContextAdapterImpl(new VelocityContext()), runtimeInstance);
template.setData(simpleNode);
template.merge(...);
...
To get a reader for the vm file in OSGi you should choose a class that is surely in the same bundle as your vm resource and call SameBundleClass.class.getResourceAsStream... You can transform your stream to writer with InputStreamReader than. 要获得OSGi中vm文件的读者,您应该选择一个肯定与vm资源在同一个包中的类,并调用SameBundleClass.class.getResourceAsStream ...您可以使用InputStreamReader将您的流转换为writer。
Please note that the example misses some try-catch-finally block. 请注意,该示例错过了一些try-catch-finally块。
Two things to verify 要验证两件事
Make sure you set the classpath of the OSGi bundle via the MANIFEST.MF to include a dot: 确保通过MANIFEST.MF设置OSGi包的类路径以包含一个点:
Bundle-ClassPath: .
The dot means to include the root of the bundle in the class-loading hierarchy, where your folder "velocitytemplates" likely resides. 点表示在类加载层次结构中包含bundle的根,您的文件夹“velocitytemplates”可能驻留在该层次结构中。
And you need to have the Velocity jar-files in the same bundle where your template-files reside, because otherwise you'll get classloading issues as Velocity would reside in a different bundle and thus would not see the "velocitytemplates" at all in its classpath. 并且你需要将Velocity jar文件放在模板文件所在的同一个包中,否则你会得到类加载问题,因为Velocity将驻留在另一个包中,因此根本不会看到“velocitytemplates”类路径。
ClasspathResourceLoader does not support setting a "path", as it uses the Classpath by definition, so either add "velocitytemplates" to the Classpath in the OSGi bundle (MANIFESt.MF) or reference the velocity templates with complete path, ie "velocitytemplates/index.vm" ClasspathResourceLoader不支持设置“路径”,因为它根据定义使用Classpath,因此要么将“velocitytemplates”添加到OSGi包中的Classpath(MANIFESt.MF),要么使用完整路径引用速度模板,即“velocitytemplates / index” .vm”
After 2 days I and a colleague have found the solution Velocity Engine have for default: file.resource.loader.class=org.apache.velocity.runtime.resource.loader.FileResourceLoader 2天后,我和一位同事发现了Velocity Engine默认的解决方案:file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
Created own class Resource loader like that 像这样创建自己的类Resource loader
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;
}
}
set the new context class loader 设置新的上下文类加载器
Thread.currentThread().setContextClassLoader(PdfResourceLoader.class.getClassLoader());
VelocityEngine ve = new VelocityEngine();
changed the property for default inside the velocity engine 在速度引擎内更改了默认属性
ve.setProperty("resource.loader", "pdf");
ve.setProperty("pdf.resource.loader.class",
PdfResourceLoader.class.getName());
ve.init();
Example name path template 示例名称路径模板
String pathTemplate = "/templates/yourTemplateName.html";
Template t = ve.getTemplate(pathTemplate, "UTF-8");
That it's 就是这样
I encountered a similar problem with class loader based templates where I wanted to specify a different root. 我遇到了类加载器模板的类似问题,我想指定一个不同的根。 I worked around it by subclassing ClasspathResourceLoader.
我通过继承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);
}
}
With the following properties set 设置以下属性
resource.loader=myloader
myloader.resource.loader.class=my.package.PrefixedClasspathResourceLoader
myloader.resource.loader.prefix=/velocitytemplates/
this way if you've got a template called "index.vm", velocity will use the classloader to find a resource called "/velocitytemplates/index.vm" 这样,如果你有一个名为“index.vm”的模板,velocity将使用类加载器来查找名为“/velocitytemplates/index.vm”的资源。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.