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

之前习惯使用UTF-8编码,现在团队使用GBK。

所以遇到一种场景,模板文件使用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是解决乱码问题的关键

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,字面意思理解 "模板文件的编码,用于格式化输入流";

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)方法!

接下来谈下Velocity和VelocityEngine的区别

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

从细节上,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;
} }

Velocity VelocityEngine 支持多种loader 乱码问题的更多相关文章

  1. Neutron 如何支持多种 network provider - 每天5分钟玩转 OpenStack(70)

    Neutron 的架构是非常开放的,可以支持多种 network provider,只要遵循一定的设计原则和规范.本节我们将开始讨论这个主题. 先讨论一个简单的场景:在 Neutorn 中使用 lin ...

  2. 创建支持多种屏幕尺寸的Android应用

    Android涉及各种各样的支持不同屏幕尺寸和密度的设备.对于应用程序,Android系统通过设备和句柄提供了统一的开发环境,大部分工作是校正每一个应用程序的用户界面到它显示的屏上.与此同时,系统提供 ...

  3. Android ImageCache图片缓存,使用简单,支持预取,支持多种缓存算法,支持不同网络类型,扩展性强

    本文主要介绍一个支持图片自动预取.支持多种缓存算法的图片缓存的使用及功能.图片较大需要SD卡保存情况推荐使用ImageSDCardCache. 与Android LruCache相比主要特性:(1). ...

  4. 使用AuthDBMType指令支持多种类似DBM的数据库

    Unix线程 在支持POSIX线程的Unix系统上,现在Apache能在混合的多进程.多线程模式下运行,使很多(但非全部)配置的可伸缩性得到了改善. 新的编译系统 重写了编译系统,现在是基于autoc ...

  5. search支持多种标签

    织梦的搜索页面支持dede标签的方法一 打开文件:include/arc.searchview.class.php 找到: require_once(DEDEINC."/taglib/hot ...

  6. 支持多种浏览器的纯css下拉菜单

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  7. Cassandra在CQL语言层面支持多种数据类型

    Cassandra在CQL语言层面支持多种数据类型. CQL类型 对应Java类型 描述 ascii String ascii字符串 bigint long 64位整数 blob ByteBuffer ...

  8. 【原创】C++链表如何像Python List一样支持多种数据类型

    用过Python的码友都知道,Python中List支持多种数据类型,如下面代码所示链表li内的数据类型可以是整数,同时也可以是字符串,当然也可以是其他数据类型. 1: >>> li ...

  9. android 布局如何支持多种不同屏幕尺寸

    android 布局如何支持多种不同屏幕尺寸 --关于dp.layout-xxx.drawable-xxx作用的小结 转载自:http://blog.csdn.net/vincent_blog/art ...

随机推荐

  1. 半夜思考之查漏补缺 , Spring 中的 Bean 继承机制

    这里的继承 , 不是 Java 中的继承 , 下面就总结下 Bean继承与Java继承的区别: Spring 中的子类 Bean 和父 Bean 可以是不同类型 , 但是 Java 中的继承则可保证子 ...

  2. ASP.NET MVC 模型绑定

    模型绑定指的是MVC从浏览器发送的HTTP请求中为我们创建.NET对象,在HTTP请求和C#间起着桥梁的作用.模型绑定的一个最简单的例子是带参数的控制器action方法,比如我们注册这样的路径映射: ...

  3. 【bzoj5166】[HAOI2014]遥感监测 贪心

    题目描述 给出平面上 $n$ 个圆,在x轴上选出尽可能少的点,使得每个圆中至少有一个点.求这个最小点数. 输入 第1行: N R 分别表示激光点的个数和射电望远镜能检测到的半径 第2~N+1行: Xi ...

  4. python的==和is区别

    Python中: is判断两个标识符是否引自同一个对象 ==判断两个标识符的值是否相等 区别于java: ==判断两个标识符是否引自同一个对象 .equals()判断是否相等   #如果是String ...

  5. 【CF938G】Shortest Path Queries(线段树分治,并查集,线性基)

    [CF938G]Shortest Path Queries(线段树分治,并查集,线性基) 题面 CF 洛谷 题解 吼题啊. 对于每个边,我们用一个\(map\)维护它出现的时间, 发现询问单点,边的出 ...

  6. 51nod 1589 移数博弈 | 基数排序(ノಠ益ಠ)ノ彡┻━┻

    51nod 1589 移数博弈 题面 给出一个序列a,长度 n <= 10^7, a[i] <= 10^7 求每个长度 >= 2 的区间的最大值*次大值 之和. 题解 主要思路是求每 ...

  7. vi写完文件保存时才发现是readonly😂

    在MAC上编辑apache配置文件,老是忘记sudo…… readonly的文件保存时提示 add ! to override, 但这仅是对root来说的啊! 百毒了一下竟然还有解决方案!! :w ! ...

  8. Javascript/jQuery关于JSON或数组集合的几种循环方法

    JavaScript遍历JSON或数组集合: /** * 根据json数据生成option树形控件 * 如果有children节点则自动生成树形数据 * @param {JSON} data * @p ...

  9. Android Studio下“Error:Could not find com.android.tools.build:gradle:2.2.1”的解决方法

    ref from: Android Studio下“Error:Could not find com.android.tools.build:gradle:2.2.1”的解决方法http://blog ...

  10. 解题:Poetize6 IncDec Sequence

    题面 差分原数列得到差分数组$dif$,这样对于$dif[2]->dif[n]$会多出来两个“空位置”$1$和$n+1$.然后区间加减就变成了使一个位置$+1$,另一个位置$-1$(可以对“空位 ...