All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.linpn.velocity.directive.CacheDirective Maven / Gradle / Ivy

The newest version!
package com.github.linpn.velocity.directive;

import org.apache.velocity.context.InternalContextAdapter;
import org.apache.velocity.exception.*;
import org.apache.velocity.runtime.RuntimeServices;
import org.apache.velocity.runtime.directive.Directive;
import org.apache.velocity.runtime.parser.node.Node;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.context.ContextLoader;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;


/**
 * Velocity页面缓存宏。
 * #cache('key', 分钟)
 * html_body
 * #end
 * 其中key为指定的cache key,如果为空,则以宏的使用位置(行号和列号)为key
 *
 * @author Linpn
 */
public class CacheDirective extends Directive {

    private static final String VELOCITY_CACHED_KEY = "VELOCITY_CACHED_KEY";

    private static final String CACHE_REDIS_TEMPLATE = "direcitive.cache.redistemplate";
    private static final String CACHE_EXPIRE = "direcitive.cache.expire";

    private static RedisTemplate cache;
    private String redisTemplate = "redisTemplate";
    private long expire = 5; //默认时间为5分钟

    /**
     * 指令的名称
     */
    @Override
    public String getName() {
        return "cache";
    }

    /**
     * 指令类型为块指令
     */
    @Override
    public int getType() {
        return BLOCK;
    }

    @Override
    public void init(RuntimeServices rs, InternalContextAdapter context,
                     Node node) throws TemplateInitException {
        super.init(rs, context, node);

        try {
            //获取redisTemplate对象
            Object _redisTemplate = rs.getProperty(CACHE_REDIS_TEMPLATE);
            if (_redisTemplate != null && !_redisTemplate.equals("")) {
                redisTemplate = _redisTemplate.toString();
            }

            //获取默认缓存超时时间
            Object _expire = rs.getProperty(CACHE_EXPIRE);
            if (_expire != null && isNumeric(_expire.toString())) {
                expire = Long.valueOf(_expire.toString());
            }

            //创建redisTemplate客户端
            if (cache == null) {
                cache = ContextLoader.getCurrentWebApplicationContext().getBean(redisTemplate, RedisTemplate.class);
            }
        } catch (Exception e) {
            throw new VelocityException("创建RedisTemplate出错", e);
        }
    }

    @Override
    public boolean render(InternalContextAdapter context, Writer writer, Node node)
            throws IOException, ResourceNotFoundException, ParseErrorException, MethodInvocationException {
        //获取参数
        String[] params = this.getParams(context, node);
        String key = new StringBuilder(VELOCITY_CACHED_KEY + "|" + params[0]).append(context.getCurrentTemplateName()).append(':').append(node.getLine()).append(':').append(node.getColumn()).toString();
        long expire = isNumeric(params[1]) ? Long.valueOf(params[1]) : this.expire;

        //获取缓存数据
        try {
            String value = this.getCachedValue(key);
            if (value == null) {
                Node bodyNode = getBodyNode(node);
                StringWriter sw = new StringWriter();
                bodyNode.render(context, sw);
                value = sw.toString();
                this.setCacheValue(key, value, expire);
            }
            writer.write(value);
        } catch (Exception e) {
            return false;
        }

        return true;
    }

    protected String getCachedValue(String key) {
        Object value = cache.boundValueOps(key).get();
        if (value != null) {
            return value.toString();
        } else {
            return "";
        }
    }

    protected void setCacheValue(String key, String value, long expire) {
        cache.boundValueOps(key).set(value, expire, TimeUnit.MILLISECONDS);
    }

    private String[] getParams(InternalContextAdapter context, Node node) {
        //参数个数
        String[] params = new String[2];
        int count = node.jjtGetNumChildren();
        if (count == 2) {
            params[0] = node.jjtGetChild(0).value(context).toString();
            params[1] = node.jjtGetChild(1).value(context).toString();
            return params;
        } else if (count == 1) {
            params[0] = node.jjtGetChild(0).value(context).toString();
            params[1] = "";
            return params;
        } else {
            throw new ParseErrorException("参数个数不正确!");
        }
    }

    private Node getBodyNode(Node node) {
        return node.jjtGetChild(node.jjtGetNumChildren() - 1);
    }

    private boolean isNumeric(String str) {
        if (str != null && !str.equals("")) {
            Pattern pattern = Pattern.compile("[0-9]*");
            return pattern.matcher(str).matches();
        } else {
            return false;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy