## 1.15 安全输出(重要)
[TOC]
安全输出是任何一个模板引擎必须重视的问题,否则,将极大困扰模板开发者。Beetl中,如果要输出的模板变量为null,则beetl将不做输出,这点不同于JSP,JSP输出null,也不同于Freemarker,如果没有用`!`,它会报错。
模板中还有俩种情况会导致模板输出异常
- 有时候模板变量并不存在,这时候必须报错,如果简单忽略不输出(Velocity就是这样),很容易留坑
- 模板变量为null,但输出的是此变量的一个属性,如 `${user.wife.name}`
针对前两种情况,可以在变量引用后加上 `!` 以提醒beetl这是一个安全输出的变量,变量确实有可能不存在
如 `${user.wife.name! }`,即使user不存在,或者user为null,或者user.wife为null,或者user.wife.name为null beetl都不将输出
可以在!后增加一个常量(字符串,数字类型等),或者另外一个变量,方法,本地调用,作为默认输出,譬如:
`${user.wife.name!"单身"}`,如果user为null,或者user.wife为null,或者user.wife.name为null,输出`单身`
譬如
`${user.birthday!@System.constants.DefaultBir}`, 表示如果user为null,或者user. birthday为null,输出`System.constants.DefaultBir`
还有一种情况很少发生,但也有可能,输出模板变量发生的任何异常,如变量内部抛出的一个异常
这需要使用格式${!(变量)},这样,在变量引用发生任何异常情况下,都不作输出,譬如
`${!(user.name)}`,Beetl将会调用 `user.getName()` 方法,如果发生异常,Beetl 将会忽略此异常,继续渲染
值得注意的是,在变量后加上!不仅仅可以应用于占位符输出(但主要是应用于占位符输出),也可以用于表达式中,如:
```javascript
<%
var k = user.name!'N/A'+user.age!;
%>
<%
${k}
%>
```
如果 user 为 null ,则 k 值将为`N/A`
在有些模板里,可能整个模板都需要安全输出,也可能模板的部分需要安全输出,使用者不必为每一个表达式使用!,可以使用beetl的安全指示符号来完成安全输出 如:
```javascript
<%
DIRECTIVE SAFE_OUTPUT_OPEN;
%>
${user.wife.name}
模板其他内容,均能安全输出……
<%
//关闭安全输出。
DIRECTIVE SAFE_OUTPUT_CLOSE;
%>
```
Beetl 不建议每一个页面都使用 `DIRECTIVE SAFE_OUTPUT_OPEN`,这样,如果真有不期望的错误,不容易及时发现,其次,安全输出意味着 Beetl 会有额外的代码检测值是否存在或者是否为null,性能会略差点。所以建议及时关闭安全输出(这不是必须的,但页面所有地方是安全输出,可能不容易发现错误)
如果你的所有模板都想安全输出,可以配置,但不推荐。严格了错误,就像 try-catch 吃掉异常一样不容易发现这是个错误
```
SAFE_OUTPUT=true
```
在 for-in 循环中 ,也可以为集合变量增加安全输出指示符号,这样,如果集合变量为null,也可以不进入循环体,如:
```javascript
<%
var list = null;
for(item in list!){
}elsefor{
print("no data");
}
%>
```
### 1.15.1 变量是否存在
```javascript
<%
if(has(flag)){
print("flag变量存在,可以访问")
}
%>
```
如果需要判断变量是否存在,如果存在,还有其他判断条件,通常都这么写
```javascript
<%
if(has(flag)&&flag==0){
//code
}
%>
```
如果flag存在,而且值是0,都将执行if语句
但是,有更为简便的方法是直接用安全输出,如
```javascript
<%
if(flag!0==0){
//code
}
%>
```
flag!0 取值是这样的,如果flag不存在,则为0,如果存在,则取值flag的值,类似三元表达式 if((has(flag)?flag:0)==0)
### 1.15.2 安全输出表达式
安全输出表达式可以包括
- 字符串常量,如 ${user.count!"无结果"}
- boolean常量 ${user.count!false}
- 数字常量,仅限于正数,因为如果是负数,则类似减号,容易误用,因此,如果需要表示负数,请用括号,如${user.count!(-1)}
- class直接调用,如${user.count!@User.DEFAULT_NUM}
- 方法调用,如 ${user.count!getDefault() }
- 属性引用,如 ${user.count!user.maxCount }
- 任何表达式,需要用括号
- Beetl 3 中文文档
- 第一部分 基础用法
- 1.1 安装
- 1.2 快速开始
- 1.3 模板基础配置
- 1.4 模板加载器
- 1.5 定界符与占位符
- 1.6 注释
- 1.7 变量定义
- 1.8 属性
- 1.9 数学表达式
- 1.10 循环语句
- 1.11 条件语句
- 1.12 异常捕获
- 1.13 虚拟属性
- 1.14 函数调用
- 1.15 安全输出(重要)
- 1.16 输出格式化
- 1.17 标签
- 1.18 调用Java方法与属性
- 1.19 严格MVC控制
- 1.20 指令
- 1.21 错误处理
- 1.22 Beetl小工具
- 1.23 Escape
- 第二部分 高级用法
- 2.1 配置GroupTemplate
- 2.2 自定义方法
- 2.3 自定义格式化函数
- 2.4 自定义标签
- 2.5 自定义虚拟属性
- 2.6 使用额外的资源加载器
- 2.7 自定义资源加载器
- 2.8 使用CompositeResourceLoader
- 2.9 自定义错误处理器
- 2.10 自定义安全管理器
- 2.11 注册全局共享变量
- 2.12 自定义布局
- 2.13 性能优化
- 2.14 定制输出
- 2.15 定制模板引擎
- 2.16 直接运行Beetl脚本
- 2.17 模板校验
- 第三部分 Web 集成
- 3.1 Web提供的全局变量
- 3.2 集成技术开发指南
- 3.3 Servlet集成
- 3.4 SpringMVC集成
- 3.5 Spring Boot集成
- 3.6 Jodd集成
- 3.7 JFinal4 集成方案
- 3.8 Nutz集成
- 3.9 Struts2集成
- 3.10 整合ajax的局部渲染技术
- 3.11 在页面输出错误提示信息
- 附录
- 4.1 内置方法
- 4.2 Spring相关函数
- 4.3 Spring security
- 4.4 shiro
- 4.5 内置格式化方法
- 4.6 内置标签函数
- 4.7 内置html标签
- 4.8 性能优化
- 4.9 Eclipse 插件
- 4.10 性能测试对比