最终走上了一条稍微不同的路线来解决这个问题。
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 从那里获取它已被证明更有效,并且在这种情况下相当优雅,我可以看到没有重大的性能损失。