最近升级团队的代码生成工具,此工具是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. typescript 不用import?

    如果你想用ts文件,而又不想import,export,怎么办呢? 感谢开发者提供的工具.    https://github.com/domchen/typescript-plus.   感想: 仅 ...

  2. elasticsearch6 学习之安装

    安装环境:centos6.5  64位      jdk1.8      elasticsearch6.1.1 一.启动 [root@localhost bin]# ./elasticsearch - ...

  3. JVM内存模型二

    Java 中通过多线程机制使得多个任务同时执行处理,所有的线程共享JVM内存区域main memory,而每个线程又单独的有自己的工作内存,当线程与内存区域进行交互时,数据从主存拷贝到工作内存,进而交 ...

  4. CodeForces - 988D(思维STL)

    原文地址:https://blog.csdn.net/weixin_39453270/article/details/80548442 博主已经讲的很好了 题意: 从一个序列中,选出一个集合,使得集合 ...

  5. [提升性选讲] 树形DP进阶:一类非线性的树形DP问题(例题 BZOJ4403 BZOJ3167)

    转载请注明原文地址:http://www.cnblogs.com/LadyLex/p/7337179.html 树形DP是一种在树上进行的DP相对比较难的DP题型.由于状态的定义多种多样,因此解法也五 ...

  6. Day22-Django之缓存

    由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5 ...

  7. Fork/Join框架实现原理

    ForkJoinPool由ForkJoinTask数组和ForkJoinWorkerThread数组组成,ForkJoinTask数组负责存放程序提交给ForkJoinPool的任务,而ForkJoi ...

  8. Centos7搭建redis集群及安装sentinel

    准备三个节点,系统版本为CentOS7.3 11.0.8.15 master 11.0.8.16 slave01 11.0.8.17 slave02 1.安装redis # yum install - ...

  9. 解题:JXOI 2018 游戏

    题面 From ZRQ,很好的计数题 我们可以发现这$len=r-l+1$个数中有一些是必须被查到的,即它们不是一些数的倍数,它们的数目$imp$可以通过一次埃氏筛求出. 在一个排列中可怜查到某个位置 ...

  10. 2018.9.21 Codeforces Round #511(Div.2)

    只写了AB,甚至还WA了一次A题,暴露了蒟蒻的本质=.= 感觉考的时候有好多正确或和正解有关的思路,但是就想不出具体的解法或者想的不够深(长)(怕不是过于鶸) 话说CF的E题怎么都这么清奇=.= A. ...