最近升级团队的代码生成工具,此工具是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. php in_array()优化

    开年首篇文章,后天上班了,正在调整状态.年前室友问我一段程序效率问题,刚好来研究下!该函数是关于判断域名字符串是否是单拼域名.双拼域名.三拼域名...多拼域名问题: //原始程序function pi ...

  2. 一些常用的基础Linux操作指令

    复习的时候顺便分享我学的知识,虽不是什么牛的技术分享,只是一些基础,基础打好了技术慢慢就提高了!一起加油一起共勉! 具体的vi和vim命令集太多了,以后的随笔我也会分享出来,没必要全记住,记住常用的就 ...

  3. 题解 P1208 【[USACO1.3]混合牛奶 Mixing Milk】

    其实根本没有一楼dalao描述的那么麻烦...... 一楼dalao其实吧,采用了一种纯属模拟的方式. 下面是我的大跃进思想 但是一个个地做减法是不是太慢了?(大跃进思想) 于是我们是不是可以直接进行 ...

  4. [AT697]フィボナッチ

    题目大意:给你$n,k(n\leqslant10^9,k\leqslant10^3)$,求$f_n$.$f$数组满足$f_1=f_2=\cdots=f_k=1$,$f_n=\sum\limits_{i ...

  5. 关于dismissViewControllerAnimated值得注意的一点(deinit)

    在使用dismissViewControllerAnimated退出当前视图的时候,理论上,该视图对象就会被清除了, 也就是说会进去当前类的析构函数deinit里面.但是有时候会发现,dismiss之 ...

  6. 【NOI 2018】冒泡排序(组合数学)

    题意大概是给定一个长度为$n$的排列$p$,求有多少长度为$n$的排列满足冒泡排序的交换次数为$\frac{1}{2} \sum\limits_{i = 1}^{n}|i - p_{i}|$. 可以发 ...

  7. 洛谷 P1072 Hankson 的趣味题 解题报告

    P1072 \(Hankson\)的趣味题 题目大意:已知有\(n\)组\(a0,a1,b0,b1\),求满足\((x,a0)=a1\),\([x,b0]=b1\)的\(x\)的个数. 数据范围:\( ...

  8. 【bzoj4542】 Hnoi2016—大数

    http://www.lydsy.com/JudgeOnline/problem.php?id=4542 (题目链接) 题意 给出一个素数$P$,一个数串$S$,$m$个询问,每次询问区间$[l,r] ...

  9. Spring MVC+Spring+Mybatis+MySQL(IDEA)入门框架搭建

    目录 Spring MVC+Spring+Mybatis+MySQL(IDEA)入门框架搭建 0.项目准备 1.数据持久层Mybatis+MySQL 1.1 MySQL数据准备 1.2 Mybatis ...

  10. 求n个数中前k个数,按之前的顺序输出(HK IPM)

    For smaller k: #include <cstdio> #include <cstdlib> #include <cstring> #include &l ...