Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java OSGi中的Velocity:如何从类路径加载模板_Java_Osgi_Velocity - Fatal编程技术网

Java OSGi中的Velocity:如何从类路径加载模板

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

我正在使用velocity模板引擎为OSGi开发一个应用程序。 通过文件加载器加载模板非常有效,但现在我必须在jar中实现这些模板,并将其作为资源加载

我怎样才能让它工作

我的代码:

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的内部类手动创建模板
如果不需要经常合并模板,那么可以使用第一个选项,因此性能不是关键要求

下面是第二个选项的示例,其中创建的模板对象可以通过调用其上的merge函数来重用(期望您已经获得了vm文件或资源的读取器):

要在OSGi中获取vm文件的读取器,您应该选择一个类,该类肯定与您的vm资源位于同一捆绑包中,并调用SameBundleClass.class.getResourceAsStream。。。您可以使用InputStreamReader将流转换为writer,而不是


请注意,该示例遗漏了一些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");