Velocity VelocityEngine 支持多种loader 乱码问题

最近升级团队的代码生成工具,此工具是velocity实现的。java

以前习惯使用UTF-8编码,如今团队使用GBK。apache

因此遇到一种场景,模板文件使用UTF-8(习惯了全部任性),输出文件使用GBK(项目须要)。设计模式

 

 
 
Properties props = new Properties(); 
props.setProperty(Velocity.ENCODING_DEFAULT, "GBK");//全局编码,若是如下编码不设置它就生效 props.setProperty(Velocity.INPUT_ENCODING, "UTF-8");//输入流的编码,实际上是打酱油!非模板文件编码 props.setProperty(Velocity.OUTPUT_ENCODING, "GBK");//输入流编码,很关键! props.setProperty(VelocityEngine.RESOURCE_LOADER,"file");//模板文件加载方式
VelocityEngine engine = new VelocityEngine(props);

下面这段code是解决乱码问题的关键app

Template  template = engine.getTemplate("a.vm","UTF-8");//模板文件的编码,很关键!
VelocityContext context = new VelocityContext();
context.put("a","a");
FileWriter fileWriter=new FileWriter("test.java");
template.merge(context, fileWriter);

分析:工具

 

String org.apache.velocity.runtime.RuntimeConstants.INPUT_ENCODING = "input.encoding"
 

The character encoding for the templates. Used by the parser in processing the input streams.

 

这是velocity中  INPUT_ENCODING 的doc,字面意思理解 "模板文件的编码,用于格式化输入流";this

 

Template org.apache.velocity.app.VelocityEngine.getTemplate(String name, String encoding) throws ResourceNotFoundException, ParseErrorException
 

Returns a Template from the Velocity resource management system.

Parameters:
name The file name of the desired template.
encoding The character encoding to use for the template.

这是getTemplate(String name, String encoding)的doc,字面意思理解"encoding 参数是设置模板文件的编码"
通过个人屡次实践,若是设置了 INPUT_ENCODING 为 UTF-8,直接使用getTemplate(String name)方法,结果就是输出的文件 编码没有问题,可是模板文件的中文到输出文件中就成乱码了!
换成getTemplate(String name, String encoding),传入UTF-8编码,一切正常!编码

这是一个深深的坑!以前翻遍各大博客及官方doc都没法定位这个问题的缘由!由于你们一导致用getTemplate(String name)方法!spa

 

接下来谈下Velocity和VelocityEngine的区别设计

 

Velocity和VelocityEngine均可以用来读取模板文件和输出文件,宏观上讲,Velocity是单例模式,VelocityEngine是多例模式!code

从细节上,Velocity由于是单例的设计模式,因此init方法只能执行一次,这就意味着你在整个应用程序生命周期中Velocity的配置是没法修改的!


再说下Velocity的几种Loader,主要有ClasspathResourceLoader FileResourceLoader (默认),一些不经常使用的 JarResourceLoader  DataSourceResourceLoader 及 WebappResourceLoader URLResourceLoader 

下边再说下另一个大坑

     /**
     * Key used to retrieve the names of the resource loaders to be used. In a properties file they may appear as the following:
     *
     * <p>resource.loader = file,classpath</p>
     */
    String RESOURCE_LOADER = "resource.loader";

从字面意思理解,这里能够设置file/classpath!真实的状况是,当你设置为 classpath 时,Velocity会切换成file,由于classpath是无效设置(这个让人很费解),只有设置为 class 而且设置 class.resource.loader.class 为 org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader,才会使用ClasspathResourceLoader !

综上所述,若是想实现同时支持file和class两种loader,必须使用VelocityEngine!在文件系统中没法读取到模板文件时自动切换为classPathLoader!代码以下

import java.util.Properties;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.ResourceNotFoundException;


public abstract class BaseCode {
    {
        initVelocity("file");
    }
    
    private void initVelocity(String loader){
        props = new Properties(); 
        props.setProperty(Velocity.ENCODING_DEFAULT, "GBK");
        props.setProperty(Velocity.INPUT_ENCODING, "GBK");
        props.setProperty(Velocity.OUTPUT_ENCODING, "GBK");
        props.setProperty(VelocityEngine.RESOURCE_LOADER,loader);
        if(loader.equals("class")){
            props.setProperty("class.resource.loader.class","org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        }
        engine = new VelocityEngine(props);
    }
    
    private String templetPath;
    private Template template;
    protected static VelocityEngine engine;  
    
    protected static Properties props ;
    
    public String getTempletPath() {
        return templetPath;
    }

    public void setTempletPath(String templetPath) {
        this.templetPath = templetPath;
    }
    
    protected  Template getTemplate(){
        if(this.template==null){
            try
            { 
               template = engine.getTemplate(this.getTempletPath(),"GBK");
            }
            catch(ResourceNotFoundException e ){
                initVelocity("class");
                getTemplate();
            }
        }
        return template;
            
    }
    
    protected VelocityContext getVelocityContext(){
        VelocityContext context = new VelocityContext();
        context.put( "nameUtil", NameUtil.get() );
        return context;
    }

}
相关文章
相关标签/搜索