Beetl自定义ResourceLoader,实现特殊的模板加载需求

Beetl自定义ResourceLoader,实现特殊的模板加载需求。

如:加载jar里面的模板文件,解决“找不到指定模板或者加载模板错(TEMPLATE_LOAD_ERROR)”问题。

1.问题:

找不到指定模板或者加载模板错(TEMPLATE_LOAD_ERROR)

2.解决方案:

自定义ResourceLoader,支持从别的jar文件里面加载模板。(跨jar文件加载模板

    public static void generate(String templateFilePath, String outputFilePath, Map<String, Object> bindAttrs) throws IOException {
//        ClasspathResourceLoader resourceLoader = new ClasspathResourceLoader("template");
//        FileResourceLoader resourceLoader = new FileResourceLoader(getPath(templateFilePath));
        AppResourceLoader resourceLoader = new AppResourceLoader(getPath(templateFilePath));

        Configuration cfg = Configuration.defaultConfiguration();
        GroupTemplate groupTemplate = new GroupTemplate(resourceLoader, cfg);
        Template template = groupTemplate.getTemplate(getFile(templateFilePath));
        template.fastBinding(bindAttrs);

        File outputFile = new File(outputFilePath);
        FileWriterWithEncoding writer = new FileWriterWithEncoding(outputFile, "utf-8");
        template.renderTo(writer);
    }

3.具体代码:

AppResourceLoader
import org.beetl.core.GroupTemplate;
import org.beetl.core.Resource;
import org.beetl.core.ResourceLoader;
import org.beetl.core.misc.BeetlUtil;

import java.io.File;
import java.net.URL;
import java.util.Map;

/**
 * 自定义的ResourceLoader,用于支持从文件,jar和数据库里加载模板。
 *
 * @author Neoman
 */
public class AppResourceLoader implements ResourceLoader {
    private String root = null;
    boolean autoCheck = false;
    //模板来自文件
    boolean fromFile = true;
    //模板来自Db
    boolean fromDb = false;
    //模板来自jar包
    boolean fromJar = false;

    protected String charset = "UTF-8";
    String functionRoot = "functions";
    GroupTemplate gt = null;
    String functionSuffix = "fn";
    ClassLoader classLoader = null;

    /**
     * 使用加载beetl.jar的classloader,以及默认root为根目录
     */
    public AppResourceLoader() {
        //保留,用于通过配置构造一个ResouceLoader
        classLoader = this.getClass().getClassLoader();
        this.root = "";

    }

    /**
     * 使用指定的classloader
     *
     * @param classLoader
     */
    public AppResourceLoader(ClassLoader classLoader) {

        this.classLoader = classLoader;
        this.root = "";

    }

    /**
     * 使用指定的classloader和root
     *
     * @param classLoader
     * @param root        模板路径,如/com/templates/
     */
    public AppResourceLoader(ClassLoader classLoader, String root) {

        this.classLoader = classLoader;
        this.root = root;

    }

    /**
     * @param classLoader
     * @param root
     * @param charset
     */
    public AppResourceLoader(ClassLoader classLoader, String root, String charset) {

        this(classLoader, root);
        this.charset = charset;
    }

    /**
     * @param root ,/com/templates/如其后的resourceId对应的路径是root+"/"+resourceId
     */
    public AppResourceLoader(String root) {

        this();
        if (root.equals("/")) {
            this.root = "";
        } else {
            this.root = root;
        }

    }

    public AppResourceLoader(String root, String charset) {

        this(root);
        this.charset = charset;
    }

    /*
     * (non-Javadoc)
     *
     * @see org.beetl.core.ResourceLoader#getResource(java.lang.String)
     */
    @Override
    public Resource getResource(String key) {
        AppResource resource = new AppResource(root, key, this);
        resource.setFromFile(fromFile);
        resource.setFromDb(fromDb);
        resource.setFromJar(fromJar);
        return resource;
    }

    /*
     * (non-Javadoc)
     *
     * @see org.beetl.core.ResourceLoader#close()
     */
    @Override
    public void close() {
        // TODO Auto-generated method stub

    }

    @Override
    public boolean isModified(Resource key) {
        if (this.autoCheck) {
            return key.isModified();
        } else {
            return false;
        }
    }

    public boolean isAutoCheck() {
        return autoCheck;
    }

    public void setAutoCheck(boolean autoCheck) {
        this.autoCheck = autoCheck;
    }

    public String getRoot() {
        return root;
    }

    @Override
    public void init(GroupTemplate gt) {
        Map<String, String> resourceMap = gt.getConf().getResourceMap();
        if (resourceMap.get("root") != null) {
            String temp = resourceMap.get("root");
            if (temp.equals("/") || temp.length() == 0) {

            } else {

                if (this.root.endsWith("/")) {
                    this.root = this.root + resourceMap.get("root");
                } else {
                    this.root = this.root + "/" + resourceMap.get("root");
                }

            }

        }

        if (this.charset == null) {
            this.charset = resourceMap.get("charset");

        }

        this.functionSuffix = resourceMap.get("functionSuffix");

        this.autoCheck = Boolean.parseBoolean(resourceMap.get("autoCheck"));
        this.functionRoot = resourceMap.get("functionRoot");
        //初始化functions
        URL url = classLoader.getResource("");
        this.gt = gt;

        if (url != null && url.getProtocol().equals("file")) {

            File fnRoot = new File(url.getFile() + File.separator + root + File.separator + this.functionRoot);
            if (fnRoot.exists()) {
                String ns = "";
                String path = "/".concat(this.functionRoot).concat("/");
                BeetlUtil.autoFileFunctionRegister(gt, fnRoot, ns, path, this.functionSuffix);
            }

        }
    }

    @Override
    public boolean exist(String key) {
        URL url = this.classLoader.getResource(root + key);
        if (url == null) {
            //兼容以前的
            url = this.classLoader.getClass().getResource(root + key);
        }

        return url != null;
    }

    public String getCharset() {
        return charset;
    }

    public void setCharset(String charset) {
        this.charset = charset;
    }

    @Override
    public String getResourceId(Resource resource, String id) {
        if (resource == null)
            return id;
        else
            return BeetlUtil.getRelPath(resource.getId(), id);
    }

    public ClassLoader getClassLoader() {
        return classLoader;
    }

    public void setClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    @Override
    public String getInfo() {
        return "ClassLoader:" + this.classLoader + " Path:" + root;
    }

    public boolean isFromFile() {
        return fromFile;
    }

    public void setFromFile(boolean fromFile) {
        this.fromFile = fromFile;
    }

    public boolean isFromDb() {
        return fromDb;
    }

    public void setFromDb(boolean fromDb) {
        this.fromDb = fromDb;
    }

    public boolean isFromJar() {
        return fromJar;
    }

    public void setFromJar(boolean fromJar) {
        this.fromJar = fromJar;
    }

}
AppResource
import org.beetl.core.Resource;
import org.beetl.core.ResourceLoader;
import org.beetl.core.exception.BeetlException;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 模板资源读取,支持从db,文件,classpath,jar 里读取模板资源:
 * 先从webroot的文件里读取,如果没有,则读取数据库,如何还找不到,读取jar或者classpath里的
 *
 * @author Neoman
 */
public class AppResource extends Resource {
    String root = null;

    File file = null;
    long lastModified = 0;
    //模板来自文件
    boolean fromFile = true;
    //模板来自Db
    boolean fromDb = false;
    //模板来自jar包
    boolean fromJar = false;

    public AppResource(String root, String key, ResourceLoader resourceLoader) {
        super(key, resourceLoader);
        this.root = root;
    }

    @Override
    public Reader openReader() {
        InputStream is = null;
        Reader br;
        AppResourceLoader loader = (AppResourceLoader) this.resourceLoader;
        String filepath = root + File.separator + id;
        try {    //从文件里读取,一般的web root里
//            file = new File(PathKit.getWebRootPath() + root, id);
            file = new File(filepath);
            if (file.exists() && fromFile) {
                is = new FileInputStream(file);
            }
            //从数据库里读取,暂未实现
            if (is == null && fromDb) {

            }
            //从jar 里读取
            if (is == null && filepath.contains(".jar!")) {

                String[] split = filepath.split("!");
                // 模板路径
                String filename = split[1];
                filename = filename.replace("\\", "/");
                filename = filename.replace("//", "/");
                if (filename.startsWith("/")) {
                    filename = filename.substring(1);
                }

                // jar 路径
                String jarPath = split[0];
                jarPath = jarPath.replace("file:", "");
                JarFile jarFile = new JarFile(jarPath);
                Enumeration<JarEntry> entries = jarFile.entries();
                while (entries.hasMoreElements()) {
                    JarEntry entry = entries.nextElement();
                    if (entry.getName().equals(filename)) {
                        is = jarFile.getInputStream(entry);
                    }
                }
                // jarFile.close();
            }
            //从jar 或者classpath里读取
            if (is == null && fromJar) {
                ClassLoader cs = loader.getClassLoader();
                URL url = cs.getResource(filepath);
                if (url == null) {
                    //兼容以前的写法
                    url = resourceLoader.getClass().getResource(filepath);
                }
                if (url == null) {
                    BeetlException be = new BeetlException(BeetlException.TEMPLATE_LOAD_ERROR);
                    be.pushResource(this);
                    throw be;
                }
                is = url.openStream();
            }
            if (is == null) {
                BeetlException be = new BeetlException(BeetlException.TEMPLATE_LOAD_ERROR, " 模板不存在: " + loader.getInfo());
                be.pushResource(this);
                throw be;
            }
            br = new BufferedReader(new InputStreamReader(is, loader.charset));
            return br;
        } catch (UnsupportedEncodingException e) {
            return null;
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            BeetlException be = new BeetlException(BeetlException.TEMPLATE_LOAD_ERROR, " 模板根目录为 " + loader.getRoot());
            be.pushResource(this);
            throw be;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            BeetlException be = new BeetlException(BeetlException.TEMPLATE_LOAD_ERROR, " 模板根目录为 " + loader.getRoot());
            be.pushResource(this);
            throw be;
        }
    }

    /**
     * 目前,只能跟踪文件的变化
     */
    @Override
    public boolean isModified() {
        if (fromFile && file != null && file.exists()) {
            return file.lastModified() != this.lastModified;
        }
//		String refresh = SysConfig.dao.queryConfig("beetl.template.refresh", "0");
//		if (!"0".equals(refresh)) {//不等于0,刷新模板
//			SysConfig.dao.updateConfig("beetl.template.refresh", "0");
//			return true;
//		}
        //jar里,肯定要重启了
        if (fromJar) {
            return false;
        }
        //db里 判断时间--暂未 实现
        if (fromDb) {
            return false;
        }

        return false;
    }

    @Override
    public String getId() {
        return id;
    }

    public boolean isFromFile() {
        return fromFile;
    }

    public void setFromFile(boolean fromFile) {
        this.fromFile = fromFile;
    }

    public boolean isFromDb() {
        return fromDb;
    }

    public void setFromDb(boolean fromDb) {
        this.fromDb = fromDb;
    }

    public boolean isFromJar() {
        return fromJar;
    }

    public void setFromJar(boolean fromJar) {
        this.fromJar = fromJar;
    }

}
CommonUtils
import com.central.generator.utils.AppResourceLoader;
import org.apache.commons.io.output.FileWriterWithEncoding;
import org.apache.commons.lang3.StringUtils;
import org.beetl.core.Configuration;
import org.beetl.core.GroupTemplate;
import org.beetl.core.Template;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.util.Map;

public class CommonUtils {
    public CommonUtils() {
    }

    public static String getPath(String filePath) {
        String path = "";
        if (StringUtils.isNotBlank(filePath)) {
            path = filePath.substring(0, filePath.lastIndexOf("/") + 1);
        }

        return path;
    }

    public static String getFile(String filePath) {
        String file = "";
        if (StringUtils.isNotBlank(filePath)) {
            file = filePath.substring(filePath.lastIndexOf("/") + 1);
        }

        return file;
    }

    public static void generate(String templateFilePath, String outputFilePath, Map<String, Object> bindAttrs) throws IOException {
//        ClasspathResourceLoader resourceLoader = new ClasspathResourceLoader("template");
//        FileResourceLoader resourceLoader = new FileResourceLoader(getPath(templateFilePath));
        AppResourceLoader resourceLoader = new AppResourceLoader(getPath(templateFilePath));

        Configuration cfg = Configuration.defaultConfiguration();
        GroupTemplate groupTemplate = new GroupTemplate(resourceLoader, cfg);
        Template template = groupTemplate.getTemplate(getFile(templateFilePath));
        template.fastBinding(bindAttrs);

        File outputFile = new File(outputFilePath);
        FileWriterWithEncoding writer = new FileWriterWithEncoding(outputFile, "utf-8");
        template.renderTo(writer);
    }

    public static void main(String[] args) throws Exception {
        String templateFilePath = "file:D:\\tools_new\\maven\\config-3.0.0-20240702.031116-17.jar!\\template\\Entity.java.btl";
//        String templateFilePath = "D:/tools_new/maven/config-3.0.0-20240702.031116-17.jar!/template/Entity.java.btl";
//        String templateFilePath = "D:\\tools_new\\maven\\config-3.0.0-20240702.031116-17.jar!\\template\\Entity.java.btl";
//        File file = new File(templateFilePath);
//        Reader br = new BufferedReader(new InputStreamReader(new FileInputStream(file),  "utf-8"));
//        System.out.println(br);

        AppResourceLoader resourceLoader = new AppResourceLoader(getPath(templateFilePath));

        BufferedReader reader = (BufferedReader) resourceLoader.getResource(getFile(templateFilePath)).openReader();
        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
        reader.close();
    }
}

部分代码来源:

Beetl自定义ResourceLoader,实现特殊的模板加载需求-CSDN博客

如果您想要更加灵活地指定Velocity模板的路径,可以自定义一个模板加载器(`org.apache.velocity.runtime.resource.loader.ResourceLoader`),然后在Velocity的配置文件中使用该加载器。 以下是一个示例实现,展示了如何创建一个自定义模板加载器: ```java public class MyResourceLoader extends ResourceLoader { private String basePath; public void init(ExtendedProperties configuration) { basePath = configuration.getString("base_path", "/path/to/templates"); } public InputStream getResourceStream(String templateName) throws ResourceNotFoundException { InputStream inputStream = null; try { File file = new File(basePath, templateName); inputStream = new FileInputStream(file); } catch (Exception e) { throw new ResourceNotFoundException("Could not load template: " + templateName, e); } return inputStream; } public boolean isSourceModified(Resource resource) { return false; // 不检查模板文件是否被修改 } public long getLastModified(Resource resource) { return 0; // 永远返回0,因为我们不检查模板文件的修改时间 } } ``` 在上面的示例中,我们创建了一个名为 `MyResourceLoader` 的自定义模板加载器。该加载器使用一个基准路径(`basePath`)来指定模板文件所在的目录。在 `getResourceStream` 方法中,我们将基准路径和模板文件名组合起来,然后使用 `FileInputStream` 来加载模板文件。在 `isSourceModified` 和 `getLastModified` 方法中,我们不进行任何检查,直接返回固定的值。 接下来,在Velocity的配置文件中,我们需要将自定义加载器配置为模板加载器。以下是一个示例配置文件: ``` resource.loader = myloader myloader.resource.loader.class = com.example.MyResourceLoader myloader.base_path = /path/to/templates ``` 在上面的示例中,`resource.loader` 属性被设置为 `myloader`,表示我们使用自定义模板加载器。`myloader.resource.loader.class` 属性被设置为 `com.example.MyResourceLoader`,表示我们使用 `MyResourceLoader` 类来加载模板。`myloader.base_path` 属性被设置为静态模板路径,例如 `/path/to/templates`。 通过以上配置,当使用Velocity引擎来渲染模板时,它会使用自定义模板加载器来加载模板文件。例如,如果我们有一个名为 `mytemplate.vm` 的模板文件,可以使用以下代码来渲染它: ``` VelocityEngine engine = new VelocityEngine(); engine.setProperty("resource.loader", "myloader"); engine.setProperty("myloader.resource.loader.class", "com.example.MyResourceLoader"); engine.setProperty("myloader.base_path", "/path/to/templates"); engine.init(); Template template = engine.getTemplate("mytemplate.vm"); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值