所以我只是开始使用Velocity并尝试通过一个简单的小实验来解决它。现在直接从文件加载模板证明了一些破坏,所以我通过StringResourceLoader取而代之。
servletContext = ServletActionContext.getServletContext();
//Set up Velocity
VelocityEngine ve = new VelocityEngine();
ve.setProperty ("runtime.log.logsystem.class", "org.apache.velocity.runtime.log.NullLogSystem");
ve.setProperty ("resource.loader", "string");
ve.setProperty ("string.resource.loader.class", "org.apache.velocity.runtime.resource.loader.StringResourceLoader");
ve.init();
//get a template
StringResourceRepository repo = StringResourceLoader.getRepository();
String templateName = "documentReminder";
String templateContent = getTemplateContent(); //fetches a string from a file
repo.putStringResource(templateName, templateContent); //the resource.loader = string makes this work
Template template = ve.getTemplate(templateName);
//add data to context
VelocityContext vContext = new VelocityContext();
vContext.put("name", "Bob");
//render template into a Stringwriter and spit it out to screen
StringWriter writer = new StringWriter();
template.merge(vContext, writer);
PrintWriter out = response.getWriter();
out.print(writer.toString());
模板很简单:
<h1>Hi $name</h1>
我从日志中挖掘出以下内容:
DEBUG velocity:155 - Null reference [template 'documentReminder', line 9, column 16] : $name cannot be resolved.
现在,这将很乐意获取模板,但不更改地将其吐出,而不插入名称。有没有人有任何建议?
答案 0 :(得分:0)
结束了一条稍微不同的路线来解决这个问题。
public class TemplateParser {
public static final TemplateParser INSTANCE = new TemplateParser();
private static final String TEMPLATE_PATH_BASE = "WEB-INF/velocitytemplates/";
private Logger logger = Logger.getLogger(getClass());
public static final String TEMPLATE_DOCUMENT_REMINDER = "document_reminder";
private HashMap<String, String> templates = new HashMap<String, String>(); //will be lazy-loading these
private static final Map<String, String> templatePaths; //populate in the {static} and make unmodifiable
static{
HashMap<String, String> pathsTemp = new HashMap<String, String>();
pathsTemp.put(TEMPLATE_DOCUMENT_REMINDER, "documentReminder.html.vm");
templatePaths = Collections.unmodifiableMap(pathsTemp);
}
/**
* Set up the template parser. Singleton model. Velocity properties are set here.
*/
protected TemplateParser(){
//set up log4j - if we don't set up logging it crashes with a nullpointerexception
Velocity.setProperty ("runtime.log.logsystem.class", "org.apache.velocity.runtime.log.SimpleLog4JLogSystem");
Velocity.setProperty ("runtime.log.logsystem.log4j.category", "velocity");
Velocity.setProperty ("runtime.log.logsystem.log4j.logger", "velocity");
try {
Velocity.init();
} catch (Exception e){
logger.debug ("Problems initialising velocity for com.etime.util.TemplateParser");
}
logger.debug("com.etime.util.MailTemplateParser initialised");
}
/**
* Get the active instance of this object as per singleton model
* @return TemplateParser
*/
public static TemplateParser getInstance(){
return INSTANCE;
}
/**
* Parse a template. Pass a VelocityContext and template name (all listed as static strings).
* @param context Create and pass a new VelocityContext - essentially a map <String, Object>
* @param template Find template names in the static strings for the TemplateParser class
* @return A parsed template as a string to do with as you see fit
*/
public String parse(VelocityContext context, String template){
String templateContent = getTemplateContent(template);
//Parse the template and handle errors where present
StringWriter w = new StringWriter();
try {
Velocity.evaluate(context, w, "TemplateParserLog", templateContent); //the lazy way, but it works
} catch (ParseErrorException e) {
logger.debug("ParseError " + e);
e.printStackTrace();
} catch (MethodInvocationException e) {
logger.debug("MethodInvocationException " + e);
e.printStackTrace();
} catch (Exception e) {
logger.debug("Unknown Exception " + e);
e.printStackTrace();
}
return w.toString();
}//parse
/**
* Fetch the template content, either from the cached copy (templates) or direct through the file.
* @param template
* @return
*/
private String getTemplateContent(String template) {
ServletContext servletContext = ServletActionContext.getServletContext(); //get this so paths don't suck
String content = templates.get(template); //fetch pre-fetched template if existent
if (content == null){ //not already got content, let's load it lazily
String templatePath = templatePaths.get(template);
if (templatePath != null){
BufferedReader br = null;
try {
String fullTemplatePath = servletContext.getRealPath(TEMPLATE_PATH_BASE+templatePath); //get a proper path
br = new BufferedReader(new FileReader(fullTemplatePath)); //read file to a BufferedReader
//Push out bufferedReader to a string [content]
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append("\n");
line = br.readLine();
}
content = sb.toString();
br.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}//template path exists
}//not already got content, let's load it lazily
return content;
}//getTemplateContent
}//class
然后可以创建一个VelocityContext,向其添加内容(很像android bundle tbh)并将VelocityContent.TEMPLATE_DOCUMENT_REMINDER或其他模板名称传递给解析函数来完成这项工作。这很有效。似乎依赖于资源加载器可能是狡猾的,自己处理并传递实际的字符串并让Velocity从中获取它已被证明更有效,并且在这种情况下相当优雅,没有我能看到的重大性能影响。 / p>