哪些组件可以配置?

Febit Wit 采用IoC的机制管理组件,也就是说只要是提供了setter的组件,随处都可以配置。当前现在支持属性值自动转换为以下类型:String, class, int/Integer, boolean/Boolean,以及他们的数组形式。 例如:

# 格式为 key = value
# 设置输出编码 Engine.setEncoding(String)
engine.encoding=UTF-8
# 设置默认面声明变量 Engine.setVars(String[])
engine.vars=request, response

这是一个开放的注入管理器,只要需要,就可以把配置写在这里面,然后通过Engine.get(type)得到配置的实例

组件如果标记了 `@org.febit.wit.Init 同时还会在配置注入完成之后执行

获取引擎实例

Engine.create("配置文件列表", 额外的参数Map)

1.配置文件列表

缺省配置文件:default.wim

2.额外的参数Map

一段配置文件节选(仅演示,非实际配置)

# 以#开头的是行注释


# 设置了一个数值
DEFAULT_ENCODING=UTF-8

# @开头的一般都有特殊意义
# 依赖的模块列表
@modules=

# 设置一个参数: 类型.字段名=值
# 和 properties 一样
engine.looseVar=false

# 例如 @global 被用来声明哪些是全局组件
# IoC 会自动注入到需要这些组件的字段,例如 NativeFactory.nativeSecurityManager
@global='''
    engine
    logger
    loader
    resolverManager
    textStatement
    global
'''

# 这里先设置区段 [engine], 这样就可以简短书写了
# 区段中 : 用来定义类型继承自那个类型
#   也可以是定义过类型的区段(实例化的时候总得一层层找到他的类型, 对吧。)
[engine :org.febit.wit.Engine]
encoding=${DEFAULT_ENCODING}
# looseVar=false
# trimCodeBlockBlankLine=true
# vars=
# inits=
# shareRootData=true

# 这里就是个例子,loader 继承自routeLoader包括类型和其他参数
# 另外还记得前面 loader 被添加到全局组件了吧
# 不要担心会有多个 routeLoader, 如果没有`Engine.get("routeLoader")`, 它只是个配置,并不会被实例化
# 不过, Engine.get("loader") 和 Engine.get("routeLoader") 不是同一个实例
# 这个继承关系可以在以后被覆盖,无状态,不会有之前的继承参数
# 例如 改成 [loader :servletLoader]
[loader :routeLoader]
# 日志组件的实现
[logger :simpleLogger]
# 更改日志组件为 slf4j
[logger :slf4jLogger]

[textStatement :simpleTextStatement]

# 下面你可以当做是定义了别名, 以后就可以使用别名了,不用写包名,是不是很省劲
[simpleLogger :org.febit.wit.loggers.impl.SimpleLogger]
[slf4jLogger :org.febit.wit.loggers.impl.Slf4jLogger]
[commonLogger :org.febit.wit.loggers.impl.CommonLogger]

[pathLoader]
encoding=${DEFAULT_ENCODING}
assistantSuffixs+=.wit
suffix=.wit
# appendLostSuffix=false
# root=your/template/path

[classpathLoader :org.febit.wit.loaders.impl.ClasspathLoader]
# @extends 仅仅会把参数继承过来,不会继承类型,覆盖无状态,可以是个列表
@extends=pathLoader

[stringLoader :org.febit.wit.loaders.impl.StringLoader]

# 为了更直观可以使用 \ 转义看不见的换行符
# 当然不换行也是可以的
[resolverManager]
resolvers=\
  org.febit.wit.resolvers.impl.LongOutResolver,\
  org.febit.wit.resolvers.impl.IntegerOutResolver

# 这里 "DEFAULT_ENCODING" 又被使用了一次
# 先设置区段[]为空
[]
# 又可以使用完整的“类型.字段名”了
resolverManager.ignoreNullPointer=true

关于配置文件

采用内置的Jodd-props, 文法类似于ini

区段头

使用插值(宏)

多行模式

列表值的附加

属性继承

[classpathLoader :org.febit.wit.loaders.impl.ClasspathLoader]
@extends=pathLoader

这样将会使得 classpathLoader 继承所有以”pathLoader.”开头的所有配置

注意:这种继承之间的附加操作”+=” 是无效的,原生的将直接覆盖掉继承来的值

依赖模块的

@modules +='''
lib-assert.wim
lib-type.wim
lib-cache.wim
'''

常用配置一览

DEFAULT_ENCODING 字符串 默认编码
engine.encoding 字符串 输出编码
engine.looseVar Boolean 是否启用宽松的变量声明
engine.trimCodeBlockBlankLine Boolean 是否删除指令所占行
engine.textStatementFactory 类型 TextStatment生成器
engine.vars 列表 免声明变量名
engine.inits 列表 初始化模板
engine.shareRootData Boolean 对子模版共享传入的参数
routeLoader.defaultLoader 类型 路由加载器的缺省加载器
routeLoader.loaders 路由规则 路由加载器的路由规则
resolverManager.resolvers 类型列表 bean属性解释器
resolverManager.ignoreNullPointer Boolean 是否忽略属性读取时bean为null的异常
global.registers 类型列表 全局变量/常量 注册器
nativeSecurity.list 列表 Native黑白名单

资源加载器加载器

基本的资源加载器

## Classpath 资源加载
[classpathLoader]
# 模板根路径
root=your/template/path

## Web 根目录 资源加载
[servletLoader]
root=/your/template/path

## 普通文件系统 资源加载
[fileLoader]
root=/your/template/path

Loader路由:routeLoader

# 新增两个 loader, 继承自 classpathLoader
[classpathLoader-root :classpathLoader]
[classpathLoader-root2 :classpathLoader]

# 同上,还可以修改参数
[codeLoader :stringLoader]
codeFirst=true

# routeLoader 已经配置为全局 loader
# [loader :routeLoader]
# 改成其他的可以使用:
# [loader :classpathLoader]
# ^ 这样 所有资源直接使用 classpathLoader 来加载,不会走 routeLoader

[routeLoader]
# 缺省的Loader
default=classpathLoader
# 路由规则
loaders +='''
  classpath:   classpathLoader-root
  classpath2:  classpathLoader-root2
  /sub/path    classpathLoader-root
  str:         stringLoader
  code:        codeLoader
'''

以上面的配置为例:”classpath:/a.wit”,”/sub/path/a.wit” 都将会使用”classpathLoader”加载”/a.wit”; “code:var a =1;”将会作为字符串模版被加载为”var a =1;”;”classpath2:/b.wit” 将会使用”classpathLoader-root2”进行加载,其余的如 “/a.wit” “/b/sub/path/a.wit” 会使用缺省的”classpathLoader” 进行加载

延迟模版过期检查:lazyLoader

可以包裹一个普通loader,并设置一定时间内不检查更新(使用一些检查成本较高的模板时非常有用)

简单的安全过滤:simpleSecurityLoader

可以包裹一个普通loader,并设置安全名单

全局常量/变量/函数注册

首先,继承接口GlobalRegister

然后在方法void regist(GlobalManager manager)中进行注册

//如:
public void regist(final GlobalManager manager) {

	//全局变量
	SimpleBag globalBag = manager.getGlobalBag();
	globalBag.set("MY_GLOBAL", "MY_GLOBAL");
	globalBag.set("MY_GLOBAL_2", "MY_GLOBAL_2");

	//全局常量
	SimpleBag constBag = manager.getConstBag();
	constBag.set("MY_CONST", "MY_CONST");
	constBag.set("MY_CONST_2", "MY_CONST_2");

	//全局Native 函数
	constBag.set("new_list", this.nativeFactory.createNativeConstructorDeclare(ArrayList.class, null));
	constBag.set("list_size", this.nativeFactory.createNativeMethodDeclare(List.class, "size", null));
	constBag.set("list_add", this.nativeFactory.createNativeMethodDeclare(List.class, "add", new Class[]{Object.class}));
	constBag.set("substring", this.nativeFactory.createNativeMethodDeclare(String.class, "substring", new Class[]{int.class, int.class}));
	
	//全局自定函数
  constBag.set("is_bool", new MethodDeclare() {

      public Object invoke(Context context, Object[] args) {
          return ArrayUtil.get(args, 0, null) instanceof Boolean;
      }
  });
}

配置文件里注册该注册器

[global]
registers+= my.pkg.MyGlobalRegister

TextStatment工厂

TextStatment的作用是缓存模版文件中的文本片段,根据最终输出的类型不同可分别保存成不同的形式,如:char[]、byte[]。对于模版引擎的渲染,io以及编码消耗了很大一部分性能,选择一个更接近目标输出的形式有利于优化性能。

另外可以继承TextStatementFactory提供更适合自己的TextStatement

Native安全管理–黑白名单

默认配置已经添加了基本类型为白名单 示例:

# 示例白名单:
#    com.dog
#    com.cat
#    com.mouse.jerry
# 黑名单:
#    com.mouse
#    com.cat.tom

[defaultNativeSecurity]
list='''
  com.dog
  com.cat
  com.mouse.jerry
- com.mouse
- com.cat.tom
'''