templateservlet.java

来自「Groovy动态语言 运行在JVM中的动态语言 可以方便的处理业务逻辑变化大的业」· Java 代码 · 共 512 行 · 第 1/2 页

JAVA
512
字号
/*
 * $Id: TemplateServlet.java 4032 2006-08-30 07:18:49Z mguillem $
 * 
 * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
 * 
 * Redistribution and use of this software and associated documentation
 * ("Software"), with or without modification, are permitted provided that the
 * following conditions are met:
 * 
 * 1. Redistributions of source code must retain copyright statements and
 * notices. Redistributions must also contain a copy of this document.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * 
 * 3. The name "groovy" must not be used to endorse or promote products derived
 * from this Software without prior written permission of The Codehaus. For
 * written permission, please contact info@codehaus.org.
 * 
 * 4. Products derived from this Software may not be called "groovy" nor may
 * "groovy" appear in their names without prior written permission of The
 * Codehaus. "groovy" is a registered trademark of The Codehaus.
 * 
 * 5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
 * 
 * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *  
 */
package groovy.servlet;

import groovy.text.SimpleTemplateEngine;
import groovy.text.Template;
import groovy.text.TemplateEngine;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Writer;
import java.util.Date;
import java.util.Map;
import java.util.WeakHashMap;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * A generic servlet for serving (mostly HTML) templates.
 * 
 * <p>
 * It delegates work to a <code>groovy.text.TemplateEngine</code> implementation 
 * processing HTTP requests.
 *
 * <h4>Usage</h4>
 * 
 * <code>helloworld.html</code> is a headless HTML-like template
 * <pre><code>
 *  &lt;html&gt;
 *    &lt;body&gt;
 *      &lt;% 3.times { %&gt;
 *        Hello World!
 *      &lt;% } %&gt;
 *      &lt;br&gt;
 *    &lt;/body&gt;
 *  &lt;/html&gt; 
 * </code></pre>
 * 
 * Minimal <code>web.xml</code> example serving HTML-like templates
 * <pre><code>
 * &lt;web-app&gt;
 *   &lt;servlet&gt;
 *     &lt;servlet-name&gt;template&lt;/servlet-name&gt;
 *     &lt;servlet-class&gt;groovy.servlet.TemplateServlet&lt;/servlet-class&gt;
 *   &lt;/servlet&gt;
 *   &lt;servlet-mapping&gt;
 *     &lt;servlet-name&gt;template&lt;/servlet-name&gt;
 *     &lt;url-pattern&gt;*.html&lt;/url-pattern&gt;
 *   &lt;/servlet-mapping&gt;
 * &lt;/web-app&gt;
 * </code></pre>
 * 
 * <h4>Template engine configuration</h4>
 * 
 * <p>
 * By default, the TemplateServer uses the {@link groovy.text.SimpleTemplateEngine}
 * which interprets JSP-like templates. The init parameter <code>template.engine</code>
 * defines the fully qualified class name of the template to use:
 * <pre>
 *   template.engine = [empty] - equals groovy.text.SimpleTemplateEngine
 *   template.engine = groovy.text.SimpleTemplateEngine
 *   template.engine = groovy.text.GStringTemplateEngine
 *   template.engine = groovy.text.XmlTemplateEngine
 * </pre>
 * 
 * <h4>Logging and extra-output options</h4>
 *
 * <p>
 * This implementation provides a verbosity flag switching log statements.
 * The servlet init parameter name is:
 * <pre>
 *   generate.by = true(default) | false
 * </pre>
 * 
 * @see TemplateServlet#setVariables(ServletBinding)
 * 
 * @author Christian Stein
 * @author Guillaume Laforge
 * @version 2.0
 */
public class TemplateServlet extends AbstractHttpServlet {

    /**
     * Simple cache entry that validates against last modified and length
     * attributes of the specified file. 
     *
     * @author Christian Stein
     */
    private static class TemplateCacheEntry {

        Date date;
        long hit;
        long lastModified;
        long length;
        Template template;

        public TemplateCacheEntry(File file, Template template) {
            this(file, template, false); // don't get time millis for sake of speed
        }

        public TemplateCacheEntry(File file, Template template, boolean timestamp) {
            if (file == null) {
                throw new NullPointerException("file");
            }
            if (template == null) {
                throw new NullPointerException("template");
            }
            if (timestamp) {
                this.date = new Date(System.currentTimeMillis());
            } else {
                this.date = null;
            }
            this.hit = 0;
            this.lastModified = file.lastModified();
            this.length = file.length();
            this.template = template;
        }

        /**
         * Checks the passed file attributes against those cached ones. 
         *
         * @param file
         *  Other file handle to compare to the cached values.
         * @return <code>true</code> if all measured values match, else <code>false</code>
         */
        public boolean validate(File file) {
            if (file == null) {
                throw new NullPointerException("file");
            }
            if (file.lastModified() != this.lastModified) {
                return false;
            }
            if (file.length() != this.length) {
                return false;
            }
            hit++;
            return true;
        }

        public String toString() {
            if (date == null) {
                return "Hit #" + hit;
            }
            return "Hit #" + hit + " since " + date;
        }

    }

    /**
     * Simple file name to template cache map.
     */
    private final Map cache;

    /**
     * Underlying template engine used to evaluate template source files.
     */
    private TemplateEngine engine;

    /**
     * Flag that controls the appending of the "Generated by ..." comment.
     */
    private boolean generateBy;

    /**
     * Create new TemplateSerlvet.
     */
    public TemplateServlet() {
        this.cache = new WeakHashMap();
        this.engine = null; // assigned later by init()
        this.generateBy = true; // may be changed by init()
    }

    /**
     * Gets the template created by the underlying engine parsing the request.
     * 
     * <p>
     * This method looks up a simple (weak) hash map for an existing template
     * object that matches the source file. If the source file didn't change in
     * length and its last modified stamp hasn't changed compared to a precompiled
     * template object, this template is used. Otherwise, there is no or an
     * invalid template object cache entry, a new one is created by the underlying
     * template engine. This new instance is put to the cache for consecutive
     * calls.
     * </p>
     * 
     * @return The template that will produce the response text.
     * @param file
     *            The HttpServletRequest.
     * @throws ServletException
     *            If the request specified an invalid template source file 
     */
    protected Template getTemplate(File file) throws ServletException {

        String key = file.getAbsolutePath();
        Template template = null;

        /*
         * Test cache for a valid template bound to the key.
         */
        if (verbose) {
            log("Looking for cached template by key \"" + key + "\"");
        }
        TemplateCacheEntry entry = (TemplateCacheEntry) cache.get(key);
        if (entry != null) {
            if (entry.validate(file)) {
                if (verbose) {
                    log("Cache hit! " + entry);
                }
                template = entry.template;
            } else {
                if (verbose) {
                    log("Cached template needs recompiliation!");
                }
            }
        } else {
            if (verbose) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?