一、ONGL
OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个单独的开源项目。
Struts2框架使用OGNL作为默认的表达式语言,是一种功能强大的EL,可以通过简单的表达式来访问Java对象中的属性。
来源:OGNL最初是为了能够使用对象的属性名来建立 UI 组件 (component) 和 控制器 (controllers)之间的联系,简单来说就是:视图与控制器之间数据的联系。后来为了应付更加复杂的数据关系,
OGNL表达式
OGNL表达式必须写在struts2的标签中
s:property它就类似于jsp的表达式,把值输出到浏览器上。value属性中的内容不再是我们看到的字符串,它是一个OGNL表达式。如果想让它变成一个普通的字符串,在值外面套上单引号
<s:property value="OGNL-Expression"/> 这是一个OGNL表达式<br/> <s:property value="'OGNL-Expression'"/>这是一个普通的字符串<br/>
OGNL的功能
● 前提:OGNL是struts2整合的一个开源项目,所以在struts2中,要想使用OGNL表达式,必须使用Struts2标签库
<%@ taglib uri="/struts-tags" prefix="s" %>
● 支持普通方法的调用(EL表达式只能调用静态方法)
<!-- 使用普通字符串调用了获取长度的方法 --> <s:property value="'OGNL-Expression'.length()"/>
● 访问静态成员(静态属性,静态方法)
<!-- struts2默认是禁止访问静态方法,因此在struts.xml文件中开启 --> <!-- 开启静态方法调用 --> <constant name="struts.ognl.allowStaticMethodAccess"value="true"></constant>
<!--访问静态属性方式:@全类名@静态属性名称--> <!--输出int类型的最大数常量--> <s:property value="@java.lang.Integer@MAX_VALUE" /><br/>
<!--访问静态方法方式:@全类名@静态方法名--> <!--输出一个小于1的随机数--> <s:property value="@java.lang.Math@random()" />
● 操作集合对象
① 创建List对象:使用的是s:radio的标签,创建list集合;{}就相当于创建了一个list集合;list属性中的取值是一个OGNL表达式
<s:radio name="gender" list="{'男','女'}"></s:radio><br/>
② 创建Map对象:使用s:radio创建一个map ;#{}表示创建一个map;1和0作为value给raido标签的value属性赋值;男和女作为key,显示到页面的内容
<s:radio name="gender1" list="#{'1':'男','0':'女'}" />
OGNL投影
① ”?#”:过滤所有符合条件的集合,如:users.{?#this.age > 19}
② ”^#”:过滤第一个符合条件的元素,如:users.{^#this.age > 19}
③ ”(美元符)#”:过滤最后一个符合条件的元素,如:users.{$#this.age > 19}
二、Struts2标签
Struts2标签库提供了主题、模板支持,极大地简化了视图页面的编写,而且,struts2的主题、模板都提供了很好的扩展性。实现了更好的代码复用。Struts2允许在页面中使用自定义组件,这完全能满足项目中页面显示复杂,多变的需求。
Struts2的标签库有一个巨大的改进之处,struts2标签库的标签不依赖于任何表现层技术,也就是说strtus2提供了大部分标签,可以在各种表现技术中使用。包括最常用的jsp页面,也可以说Velocity和FreeMarker等模板技术中的使用。
Struts2 标签的使用:
使用 Struts2 的标签库非常简单,一般只需在 JSP 文件内使用 taglib 指令导入 Struts2 标签库即可,其导入代码如下所示:
<%@ taglib uri="/struts-tags" prefix="s" %>
在上述代码中,taglib 指令的 uri 属性用于指定引入标签库描述符文件的位置,prefix 属性用于指定引入标签库描述符文件的前缀。在 JSP 文件中,所有的 Struts2 标签都建议使用 s 作为前缀。
Struts标签分类:
● 控制标签:if、else if、else 和 iterator
控制标签用于完成条件逻辑和循环逻辑的控制,也可用于做集合的操作。
● 数据标签:property、a、debug、include、param
数据标签用于输出后台的数据和完成其他数据访问功能。
● 表单标签:form、textfield textarea、passWord、radio、reset、submit、checkboxlist、select、optgroup、file、hidden
表单标签主要用于生成 HTML 页面中的表单元素。
● 非表单标签:actionmessage、actionerror 和 fielderror
非表单标签主要用于生成非表单的可视化元素,如输出 Action 中封装的信息等。
常用标签:
● iterator(迭代标签)
用于遍历集合(java.util.Collection)List、Map、数组或枚举值(java.util.iterator);
属性:
属性 | 是否必须 | 默认值 | 类型 | 说明 |
begin | 否 | 0 | Integer | 迭代数组或集合的起始位置 |
end | 否 | 数组或集合的长度大小减1,若Step为负,则为0 | Integer | 迭代数组或集合的结束为止 |
status | 否 | false | Boolean | 迭代过程中的状态 |
step | 否 | 1 | Integer | 指定每一次迭代后索引增加的值 |
value | 否 | 无 | String | 迭代的数组或集合对象 |
var | 否 | 无 | String | 将生成的Iterator设置为page范围的属性 |
ID | 否 | 无 | String | 指定了集合的元素id,现已用var代替 |
例子:
<h4>迭代List,不使用status</h4> <s:iterator value="{'zhangsan' , 'lisi' , 'wangwu'}" > <s:property/><br> </s:iterator> <h4>迭代List,使用status</h4> <table border="1" > <tr> <th>当前元素</th> <th>当前迭代的元素的总数</th> <th>当前迭代的元素的索引</th> <th>判断当前迭代的元素是否是偶数</th> <th>判断当前迭代的元素是否是奇数</th> <th>判断当前迭代的元素是否是第一个元素</th> <th>判断当前迭代的元素是否是最后一个元素</th> </tr> <s:iterator value="{'zhangsan' , 'lisi' , 'wangwu'}" status="status" > <tr> <td><s:property/></td> <td><s:property value="#status.getCount()" /></td> <td><s:property value="#status.index" /></td><!-- 简写方式:index 不简写方式:getIndex() --> <td><s:property value="#status.isEven()" /></td> <td><s:property value="#status.odd" /></td><!-- 简写方式:odd 不简写方式:isOdd() --> <td><s:property value="#status.first" /></td> <td><s:property value="#status.last" /></td> </tr> </s:iterator> </table> <h4>迭代Map,不使用status属性, \#{}是用来构造Map的写法</h4> <s:iterator value="#{'first':'zhangsan', 'second':'lisi', 'third':'wangwu' }" > <s:property value="key" /> = <s:property value="value" /><br> </s:iterator>
● property
用于输出值栈中的对象的属性值,使用value属性来指定要输出的对象属性,如果没有指定value属性,那么默认输出栈顶对象;
属性:
名称 | 是否必须 | 默认值 | 类型 | 说明 |
default | 否 | 无 | String | 如果value属性是null,则使用default值 |
escape | 否 | true | Boolean | 是否转义输出内容中的HTML,例如当该属性的值为true时,&将被转义为& |
value | 否 | 栈顶对象 | Object | 进行求值的表达式 |
<!-- 取出栈顶对象(通常是action)的username 属性并输出,如果没有找到username属性,那么输出“游客” -->
<s:property value="username" default="游客"/>
例子:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib uri="/struts-tags" prefix="s"%> <body> <!-- 取值栈中的属性(Action中的成员属性), 需要生成Get,Set方法,不需要加范围与井号 --> 结果1: <s:property value="user.name" default="若value属性中没有取到值则输出此内容。" /> <br> <!-- 取非值栈中的属性(除了Action中的成员属性外) 需要加井号,与在获取request/session/application/attr/parameters这五个范围时,需要明确指定范围 --> 结果2: <s:property value="#request.userTow.password" /> <br> <!-- escape:是否转译 true:表示将value内的内容强制转换成字符串显示 如&会被转换为& false:表示将value值当做html代码去解析 会被被解析为& --> 结果3: <s:property value="#request.amp" escape="true" /> hearts; <br> 结果4:<!-- 这里结果为桃心符号 --> <s:property value="#request.amp" escape="false" /> hearts; <br> <!-- property标签灵活用法 --> <!-- value参数的类型是object,可以理解为这个默认是会解析成ognl表达式的 比如需要输入一个字符串string,在value里面的字符串string外面加了单引号,这样不会将string解析成ognl表达式了 --> 结果5: <s:property value="'user'" /> <br> <!-- 故value的值解析成OGNL表达式,在此表达式内,有些对象的值的使用与java代码相似,但不相同,以下取几个例子 --> 结果6: <s:property value="#request.str.length()" /> <br> 结果7: <s:property value="#request.str.substring(1,3)" /> <br> <!-- value内还可以写表达式,比如输出一个整型变量num的+1值 --> 结果8: <s:property value="#request.num+1" /> <br> <!-- value内为List集合时,取其长度 --> 结果9: <s:property value="#request.list.size" /> <br> <!-- value内为List集合时,取其内容 --> 结果10: <s:property value="#request.list.get(0).name" /> </body>
● if / else if / else
决定是否显示if标签内容;
属性:test为必填属性,是一个Boolean类型值;
<s:if test=“表达式”> …….. </s:if> <s:elseif test=“表达式”> …….. </s:elseif> <s:else> ……….. </s:else>
例子:
<!-- OGNL是通常要结合Struts 2的标志一起使用。struts2标签里不能使用EL表达式。 --> <!-- 定义一个testname属性 --> <s:set name="testname" value="%{'Java'}" /> <!-- 使用if标签判断--> <s:if test="%{#testname=='Java'}"> <div> <s:property value="%{# testname}" /> </div> </s:if> <s:elseif test="%{#testname=='Jav'}"> <div> <s:property value="%{# testname}" /> </div> </s:elseif> <s:else> <div> testname不是“Java” </div> </s:else>
● set
Set标签在某些情况下是比较有用的,例如在页面中多次引用一个复杂的表达式,我们可以将这个表达式赋给一个变量,然后直接引用变量。带来的好处就是:① 提升了性能(表达式的计算只有一次) ② 提高了代码的可读性。
属性:
名称 | 是否必须 | 默认值 | 类型 | 说明 |
name | 是 | 无 | String | 变量的名字 |
value | 否 | 栈顶对象 | Object | 指定一个表达式,计算的结果赋值给变量,如果没有指定value属性,那么默认将栈顶对象赋值给变量 |
scope | 否 | action | String | 变量的范围,可选的值为:application、session、request、page、action |
例子1:
<!-- 使用bean标签定义一个javaBean实例 --> <s:bean name="lee.Person" id="p"> <s:param name="name" value="zhangsan" /> <s:param name="age" value="29" /> </s:bean> <!-- 将p放入默认范围内 --> <s:set value="#p" name="test" /> <s:property value="#test.name" /> <br> <s:property value="#test.age" /> <br> <!-- 将p放入application范围内 --> <s:set value="#p" name="test" scope="application" /> <s:property value="#attr.test.name" /> <br> <s:property value="#attr.test.age" /> <br> <!-- 将p放入session范围内 --> <s:set value="#p" name="test" scope="session" /> ${sessionScope.test.name} <br> ${sessionScope.test.age} <br>
例子2:
<%@ taglib uri="/struts-tags" prefix="s"%> <body> <p> 将Action中成员属性:user.name的值保存到默认范围中,即Stack Context(application) </p> <s:set name="name" value="user.name" /> <!-- <s:property value="#application.name" />这种写法取不到值 --> <s:property value="#name" /> <s:property value="#attr.name" /> <p> 当指定范围类型application </p> <s:set name="nameTow" value="user.name" scope="application" /> <!-- <s:property value="#nameTow" />这种写法取不到值 --> <s:property value="#attr.nameTow" /> <s:property value="#application.nameTow" /> <p> 小结:set标签默认范围是application。 当刻意去指定范围为application时,虽然范围相同,但他们取值方式又有略微不同。 <br> 共通点:都可以使用attr <br> 区别: <br> 1)默认不指定范围的方式,取值可以不加范围标志,不能使用application范围标志打点取值。 <br> 2)指定application的方式,取值必须要加范围标志,但可以使用application范围标志打点取值。 <br> </p> </body>