最近升级团队的代码生成工具,此工具是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. 再看select语句

    select语句是整个sql中输出的最后一条语句,这条语句是在最后输出的结果集合上做计算, 这些计算都包括啥东西呢?对每个结果集合做插值计算,在做完group by和where子句之后,那么就是一个一 ...

  2. 半夜思考, 为什么建议重写 equals() 方法时, 也要重写 hashCode() 方法

    我说的半夜, 并不是真正的半夜, 指的是在我一个人的时候, 我会去思考一些奇怪的问题. 要理解 hashCode() 需要理解下面三个点: hash契约 哈希冲突 哈希可变 第一点: hash 契约指 ...

  3. 2018 焦作icpc现场赛总结

    Day 0 没有直达焦作的飞机,所以选择了先到新郑机场,再转乘城际列车.城际列车猜是专门给学生开通的吧,每天只有来和回一共两趟(所以机票选择的余地也不多).买的时候只有无座票了,本来以为会一直站着,但 ...

  4. A New Function LightOJ - 1098()

    题意 求 1 - n的的所有数的因子(不包括自身和1)和 对于一个数 i  ,以i为因子的数的个数为 n/i  因为不能包括自身 所以 减一 即  n/i-1  这样遍历每一个数 累加即可 但复杂度较 ...

  5. 【ActiveMQ】- 发布/订阅模式

    publish/subscribe 特点:A发送的消息可以被所有监听A的对象的接收,就好比学校的广播,所有的学生都可以收听校园广播信息. 消息生产者: package com.zhiwei.advan ...

  6. Alpha 完结撒花 —— 事后诸葛亮

    写在前面 林燊大哥 一路走来,好不容易,终于完结了. 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 解决的问题 用户在进店之前无法得知店铺的优劣,通过 ...

  7. 丁酉年六月十一ACM模拟赛

    似乎该写题解了.今天模拟ACM,10道题(本来还有2道被删了),9道都来自BZOJ,中间我做过2道.那么说,今天Solv.便大大增多了(但还是不如强大的Amphetamine). 题单及一句话题解如下 ...

  8. 洛谷P4382 劈配

    不知道这个Zayid是谁... 题意: 有n个人,m个导师.每个导师能接纳bi个人,每个人对于这m个导师都有一个志愿档次. 优先满足靠前的人,问到最后每个人匹配的导师是他的第几志愿. 每个人又有一个限 ...

  9. JAVA 加密算法初探DES&AES

    开发项目中需要将重要数据缓存在本地以便在离线是读取,如果不对数据进行处理,很容易造成损失.所以,我们一般对此类数据进行加密处理.这里,主要介绍两种简单的加密算法:DES&AES. 先简单介绍一 ...

  10. 实验一:使用ADO.NET方式读数据

    第一步:创建Asp.net应用程序 在VS中,点击文件->新建->项目,按如图方式选择并输入: 第二步:新建产品浏览网页窗体Listing.aspx: 在项目SportsStoreEx上点 ...