velocity使用基本来说比较简单,但在加载模板时老出问题,很多初学者经常会遇到找不到模板这种异常。本文就针对目前常用的三种模板加载方式做以说明。
一、velocity默认的加载方式(文件加载方式)
package com.velocity.test; import java.io.StringWriter; import java.util.Properties; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; /** * 从文件中加载模板文件,即velocity默认的模板文件加载方式 * @author welcome * */ public class LoaderFromFile { public static void main(String[] args) throws Exception{ //初始化参数 Properties properties=new Properties(); //设置velocity资源加载方式为file properties.setProperty("resource.loader", "file"); //设置velocity资源加载方式为file时的处理类 properties.setProperty("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.FileResourceLoader"); //实例化一个VelocityEngine对象 VelocityEngine velocityEngine=new VelocityEngine(properties); //实例化一个VelocityContext VelocityContext context=new VelocityContext(); //向VelocityContext中放入键值 context.put("username", "张三"); context.put("password", "123456789"); context.put("age", "20"); context.put("address", "陕西西安"); context.put("blog", "http://blogjava.net/sxyx2008"); //实例化一个StringWriter StringWriter writer=new StringWriter(); //从vm目录下加载hello.vm模板,在eclipse工程中该vm目录与src目录平级 velocityEngine.mergeTemplate("vm/hello.vm", "gbk", context, writer); System.out.println(writer.toString()); } }
二、从类路径加载模板文件
package com.velocity.test; import java.io.StringWriter; import java.util.Properties; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; /** * 从class(类路径)中加载模板文件 * @author welcome * */ public class LoaderFromClass { public static void main(String[] args) throws Exception{ //初始化参数 Properties properties=new Properties(); //设置velocity资源加载方式为class properties.setProperty("resource.loader", "class"); //设置velocity资源加载方式为file时的处理类 properties.setProperty("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); //实例化一个VelocityEngine对象 VelocityEngine velocityEngine=new VelocityEngine(properties); //实例化一个VelocityContext VelocityContext context=new VelocityContext(); //向VelocityContext中放入键值 context.put("username", "张三"); context.put("password", "123456789"); context.put("age", "20"); context.put("address", "陕西西安"); context.put("blog", "http://blogjava.net/sxyx2008"); //实例化一个StringWriter StringWriter writer=new StringWriter(); //从src目录下加载hello.vm模板 //假若在com.velocity.test包下有一个hello.vm文件,那么加载路径为com/velocity/test/hello.vm velocityEngine.mergeTemplate("com/velocity/test/hello.vm", "gbk", context, writer); //velocityEngine.mergeTemplate("hello.vm", "gbk", context, writer); System.out.println(writer.toString()); } }
三、从jar文件中加载模板文件
package com.velocity.test; import java.io.StringWriter; import java.util.Properties; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; /** * 从jar文件中加载模板文件 * @author welcome * */ public class LoaderFromJar { public static void main(String[] args) throws Exception{ //初始化参数 Properties properties=new Properties(); //设置velocity资源加载方式为jar properties.setProperty("resource.loader", "jar"); //设置velocity资源加载方式为file时的处理类 properties.setProperty("jar.resource.loader.class", "org.apache.velocity.runtime.resource.loader.JarResourceLoader"); //设置jar包所在的位置 properties.setProperty("jar.resource.loader.path", "jar:file:WebRoot/WEB-INF/lib/vm.jar"); //实例化一个VelocityEngine对象 VelocityEngine velocityEngine=new VelocityEngine(properties); //实例化一个VelocityContext VelocityContext context=new VelocityContext(); //向VelocityContext中放入键值 context.put("username", "张三"); context.put("password", "123456789"); context.put("age", "20"); context.put("address", "陕西西安"); context.put("blog", "http://blogjava.net/sxyx2008"); //实例化一个StringWriter StringWriter writer=new StringWriter(); //从/WebRoot/WEB-INF/lib/vm.jar中加载hello.vm模板 vm.jar的目录结构为vm/hello.vm velocityEngine.mergeTemplate("vm/hello.vm", "gbk", context, writer); System.out.println(writer.toString()); } }
velocity模板路径又一解 http://www.blogjava.net/patterns/archive/2006/11/28/velocity_template_path_another_method.html
研究hibernatesynchronizer的源码,看到他将velocity模板和编译的类一起打包在jar包中,在获得模板时使用
Xobject.class.getClassLoader().getResourceAsStream("/templates/xx.vm")获得流,然后再将转变成字符串
public static String getStringFromStream(InputStream is) throws IOException { if (null == is) return null; try { InputStreamReader reader = new InputStreamReader(is); char[] buffer = new char[1024]; StringWriter writer = new StringWriter(); int bytes_read; while ((bytes_read = reader.read(buffer)) != -1) { writer.write(buffer, 0, bytes_read); } return (writer.toString()); } finally { if (null != is) is.close(); } }
最后调用velocity的方法
Velocity.evaluate(Context context, java.io.Writer out, java.lang.String logTag, java.lang.String instring)
从而生成文件。居然不知道velocity有这样的方法,挺无知的,为了路径焦头烂额,终于得解了。总结一下技巧:
1、 Xobject.class.getClassLoader().getResourceAsStream("/templates/xx.vm")相对路径获得流;
2、 Velocity.evaluate(...)方法使用;
velocity模板路径: http://zhyt710.iteye.com/blog/235250
遇到的velocity加载模板时的路径问题。
于是查阅资料解决。最后综合velocity自己带的例子的example1和example2,改写了一个例子。怎样解决的在例子的注释中已经说的很明确。对于初学velocity的同志来说,这个例子可以是你参照学习的良好实例
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import java.io.BufferedWriter; import java.io.OutputStreamWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.Properties; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.Velocity; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.exception.MethodInvocationException; import org.apache.velocity.exception.ParseErrorException; /** * This class is a simple demonstration of how the Velocity Template Engine * can be used in a standalone application using the Velocity utility class. * * It demonstrates two of the 'helper' methods found in the org.apache.velocity.util.Velocity * class, mergeTemplate() and evaluate(). * * * @author <a href="mailto:[email protected]">Geir Magnusson Jr.</a> * @version $Id: Example2.java 463298 2006-10-12 16:10:32Z henning $ */ public class Example2 { public static ArrayList getNames() { ArrayList list = new ArrayList(); list.add("ArrayList element 1"); list.add("ArrayList element 2"); list.add("ArrayList element 3"); list.add("ArrayList element 4"); return list; } public static void main( String args[] ) { /* first, we init the runtime engine. Defaults are fine. */ Properties p = new Properties(); //设置输入输出编码类型。和这次说的解决的问题无关 p.setProperty(Velocity.INPUT_ENCODING, "UTF-8"); p.setProperty(Velocity.OUTPUT_ENCODING, "UTF-8"); //这里加载类路径里的模板而不是文件系统路径里的模板 p.setProperty("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); //也可以用下面方法指定一个绝对路径,不过这样要求你所有的模板都放在该路径下,是有局限的 //p.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, "模板路径"); try { Velocity.init(p); } catch(Exception e) { System.out.println("Problem initializing Velocity : " + e ); return; } /* lets make a Context and put data into it */ VelocityContext context = new VelocityContext(); context.put("name", "Velocity"); context.put("project", "阿帕奇"); context.put("list", getNames()); /* lets render a template */ StringWriter w = new StringWriter(); try { Velocity.mergeTemplate("example2.vm", "UTF-8", context, w ); } catch (Exception e ) { System.out.println("Problem merging template : " + e ); } System.out.println(" template : " + w ); /* * lets dynamically 'create' our template * and use the evaluate() method to render it */ //这个例子也同时告诉我们可以先从文件系统读取一个文件到字符串,然后进行我们想要的操作 String s = "We are using $project $name to render this."; w = new StringWriter(); try { Velocity.evaluate( context, w, "mystring", s ); } catch( ParseErrorException pee ) { /* * thrown if something is wrong with the * syntax of our template string */ System.out.println("ParseErrorException : " + pee ); } catch( MethodInvocationException mee ) { /* * thrown if a method of a reference * called by the template * throws an exception. That won't happen here * as we aren't calling any methods in this * example, but we have to catch them anyway */ System.out.println("MethodInvocationException : " + mee ); } catch( Exception e ) { System.out.println("Exception : " + e ); } System.out.println(" string : " + w ); /////////////////////////////////////////////////////// //其他方法: 1分别指定路径,此方法可以设定不同的路径 (也可是相对的。在eclipse下是工程目录) try { VelocityEngine velocityEngine = new VelocityEngine(); Properties properties = new Properties(); //也可以在这里指定绝对路径。当指定相对路径时, 在不同的环境下是有区别的。 //比如把程序部署到tomcat以后,相对路径相对到哪里是个很恶心的事情。 String basePath = "vm"; //可设置绝对路径 //String basePath = "F:/"; properties.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, basePath); velocityEngine.init(properties); Template template = velocityEngine.getTemplate("example2.vm"); BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(System.out)); template.merge(context, writer); writer.flush(); writer.close(); } catch (Exception e) { e.printStackTrace(); } } }