0

所以我刚刚开始使用 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.

现在这将愉快地获取模板,但将其吐出而不插入名称。有没有人有什么建议?

4

1 回答 1

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 从那里获取它已被证明更有效,并且在这种情况下相当优雅,我可以看到没有重大的性能损失。

于 2013-05-23T14:08:24.600 回答