1,Struts2标签库
1.1,概述
Struts2标签库相对于Struts1进行了巨大的改进,支持OGNL表达式,不依赖任何表现层技术(可以在各种表现层技术中使用)。
我们可以在struts2-core-xxx.jar压缩文件的META-INF目录下找到struts-tags.tld文件,这个文件里定义了Struts2的标签。
Struts2对整个标签库提供了严格的分类,Strut2把所有标签都定义在一个s标签库里。虽然Struts2把所有的标签都定义在URI为"/struts-tags"的空间下,但依然可以对Struts2标签进行简单的分类。
Struts2可以将所有标签分成三类:
(1)用户界面标签(UI标签):主要用来生成HTML元素的标签。
- 表单标签:主要用于生成HTML页面的FORM元素,以及普通表单元素的标签。
- 非表单标签:主要用于生成页面上的tree,Tab页等。
(2)非用户界面标签(非UI标签):主要用于数据访问,逻辑控制。
- 数据访问标签:主要包含用于输出值栈(ValueStack)中的值,完成国际化等功能的标签。
- 流程控制标签:主要包含用于实现分支,循环等流程控制的标签。
(3)AJAX标签:用于支持Ajax效果。
1.2,使用Struts2标签
struts2-core-2.5.26.jar下的META-INF/struts-tags.tld文件,这是Struts2的标签库定义的文件。
根据自定义标签,在标签库定义文件中<uri.../>元素很重要,该URI实际上相当于该标签库的唯一标识。 为了让JSP页面使用Struts2标签,通过jsp的代码的顶部加入以下的代码:
<%@ taglib prefix="s" uri="/struts-tags" %>
2,OGNL表达式
OGNL的全称是对象图导航语言,它是一种功能强大的开源表达式语言,同时也是Struts2的默认表达式语言。比EL(只能从域或内置对象中)表达式更强大。
OGNL的特点:
- OGNL可以存取Java任意对象的任意属性,调用Java对象的方法
- ONGL能够自动实现必要的类型转换。
OGNL上下文中的根对象可以直接访问,而引用上下文中的其他对象则需要使用“#”来标记 ;值栈中的任何对象都可以直接访问,而不需要使用 “#”。
OGNL的参数:表达式、跟对象和上下文环境。
- 表达式:表达式是OGNL的核心,所有的OGNL操作都是通过解析表达式后进行的。表达式指出了OGNL操作要做的工作。例如,name、student.name等表达式,表示取name或者student中的name的值。
- 跟对象:OGNL的取值还需要一个上下文环境。设置了Root对象,OGNL可以对Root对象进行取值或写值等操作,Root对象所在环境就是OGNL的上下文环境(Context)。根对象是OGNL要操作的对象,在表达式规定了要完成的工作后,需要指定工作的操作对象。
- 上下文环境:上下文环境规定了OGNL的操作"在哪里进行"。上下文环境Context是一个Map类型的对象,在表达式中访问Context中对象,需要使用"#"号加上对象名称,即"#对象名称"的形式。例如<s:property value="#request.name"/>中,request就是对象,这个对象取出name属性的值。
OGNL的结构:
struts2标签的属性按照下列的三个规则进行计算:
(1)所有的字符串属性类型都会解析“%{…}”这样的语法。
(2)所有的非字符属性类型都不会被解析,而是直接被看作一个OGNL表达式进行求值
(3)对于第二个规则的例外情况是,如果非字符串属性使用了“%{…}”语法,那么%{…}将被忽略,花括号中的内容将作为表达式计算。
如果大家在使用标签时, 忘记了某个属性是字符串类型,还是非字符串类型,那么有一个简单的方法,那就是不考虑它是什么类型,统一使用“%{…}”语法。
OGNL与Struts2的结合:
- Struts 2中的OGNL Context即为ActionContext
- 当Struts2接受一个请求时,会迅速创建ActionContext,再创建ValueStack、action ,然后把action存放进ValueStack,所以action的实例变量可被OGNL访问。
- StackContext(map):stack上下文,它包含一系列域对象,包括request、session、attr、application等。访问Stack Context中的对象的属性时要使用"#对象名.属性名"的方式,例如#application、#session。
2.1,值栈-ValueStack
本质是一个ArrayList,充当OGNL的root,给一次请求*享数据的功能。
之前web阶段,在servlet里面进行操作,把数据放到域对象里面,在页面中使用el表达式获取到。域对象在一定范围内存值和取值。在struts2里面提供了本身的一种存储机制,类似于域对象,是值栈可以存值和取值。在action里面把数据放到值栈里面,在页面中获取到值栈的数据。
(1)向值栈中存放数据
- 获取值栈对象,调用值栈对象里面的 set 方法,在用set方法添加值栈数据之后,会在root栈顶多一个HashMap对象。
ValueStack stack=ActionContext.getContext().getValueStack(); stack.set("username","燕双嘤");
- 获取值栈对象,调用值栈对象里面的 push 方法,调用push之后,就会在root栈顶放入一个String类型的对象!
ActionContext.getContext().getValueStack().push(xxx);
- 在action定义变量,生成变量的get方法(主要),struts2并不会在值栈root的栈顶放入新的对象,它的存储路径还是存储在action里面,所以这就起到了资源的合理应用,当想要获取name属性的时候,就会在值栈里面调用action的getName方法。这也就是为什么会在值栈里面存储action的原因了。
public class pr_action{ private String name; public String getName(){ return name; } public String execute(){ name="FireLang"; return "success"; } }
(2)向值栈中存放对象
- 第一步:定义对象变量
- 第二步:生成变量的get方法
- 第三步:在执行的方法里面向对象中设置值
public class LoginAction extends ActionSupport { private User user; public User getUser() { return user; } public void setUser(User user) { this.user = user; } public String execute(){ return "success"; } }
(3)向值栈中存放List对象
- 第一步:定义List集合变量
- 第二步:生成变量的get方法
- 第三步:在执行的方法里面向List集合设置值
public class Pr_fangList { private List<User> lu; public String execute(){ lu=new ArrayList<User>(); User u1=new User(); u1.setName("燕双嘤"); u1.setPassword("123"); lu.add(u1); User u2=new User(); u2.setName("杜马"); u2.setPassword("456"); lu.add(u2); System.out.println(lu); return "success"; } public List<User> getLu() { return lu; } }
(4)从值栈里面取数据:使用struts2的标签+OGNL表达式获取值栈数据:<s:property value="OGNL表达式"/>
- 获取set值
<!—通过直接key值,从root域里面取对应值 --> <s:property value="us"/><br><br> <s:property value="lang"/> //us、lang均为key值
- 获取push值
//这里要注意的是push方法是直接把数据存放在root中的。不像set一样可以通过key来取值。 //push的取值方法有点特殊,是通过直接把栈顶元素取出来的。 <s:property value="[0].top"/>//取第一个 <s:property value="[1].top"/>//取第二个,这里的top是root的域实体对象名称,也就是List对象的名称
- 获取action中的属性字段
<s:property value="name"/> <!-- 这里的name是OGNL表达式。表示获取action中的name字段值,必须要写get方法,因为字段读或者写的功能按照规定,都必须通过读或者写方法来给变量赋值 -->
- 获取对象
//再次强调必须要get方法。 <s:property value="us.name" /><br> <!-- value中的值是OGNL表达式 --> <s:property value="us.password" /> <!-- 获取到us对象后,再获取us中的name属性和password属性,再次强调获取字段基本上都是按照规定通过get和set方法进行操作! -->
- 获取List集合
第一种方式: //这种代码非常不好,在很多时候你永远不可能知道服务端传来的List里面到底有多少参数。 <s:property value="usl[0].name"/> <s:property value="usl[0].password"/> -------------------------------------------- 第二种方式: 类似jstl中的foreach标签 <s:iterator value="usl"> <s:property value="name"/> <s:property value="password"/> <br><hr><br> </s:iterator> -------------------------------------------- 第三种方式: /*第三种方式较第二种方式多加了一个var,根本区别就是iterator把遍历出来的值放进了值栈的第二部分空间 context,contex因为是Map结构的所以要加上一个键作为取值方式,也就是var的值作为context的键,其实这 种方式算是一种优化,不用在root中去拿值了。而第二种方式还会到root里面去拿值。速度没有在context中的快*/ <s:iterator value="usl" var="singleus"> <s:property value="#singleus.name"/> <s:property value="#singleus.password"/> </s:iterator>
2.2,“#”声明OGNL表达式
作用:访问OGNL上下文和Action上下文
主要有3种用途:
(1)能够访问OGNL上下文与ActionContext资源,相当于ActionContext.getContext()。
- parameters:包含当前HTTP请求参数的Map,#parameters.id[0]作用相当于request.getParameter("id")。
- request:包含当前HttpServletRequest的属性(attribute)的Map,#request.userName相当于request.getAttribute("userName")。
- session:包含当前HttpSession的属性(attribute)的Map, #session.userName相当于session.getAttribute("userName")。
- application:包含当前应用的ServletContext的属性的Map,#application.userName相当于application.getAttribute("userName")。
- attr:用于按page->request->session->application顺序访问其属性。#attr.userName相当于按顺序在以上三个范围(scope)内读取userName属性,直到找到为止 。
(2)用于过滤或筛选集合
例如:books.{?#this.price<20},表示所有的price<20的书。
作用:用表达式从集合中选择某些元素,并将结果保存到新的集合中。
特殊符号:?——所有满足选择逻辑的对象;^——第一个满足选择逻辑的对象;$——最后一个满足选择逻辑的对象。
(3)构造Map
创建set集合对象:
<s:set name="books" value="#{'book1':'23', 'book2':'55'}" /> <p>book1的价格是: <s:property value="#books['book1']" /></p> 注意:Set由于是无序的,所以不能使用下标获取数据即不能使用#books[0]
2.3,其他符号
$:用于在国际化资源文件中,引用OGNL表达式 。在Struts 2框架的配置文件中引用OGNL表达式。
<action name=“AddPhoto” class=“addPhoto”> <interceptor-ref name=“fileUploadStack” /> <result type=“redirect”>/register.jsp?name=${name}</result> </action>
%:显示声明OGNL表达式。某些标签种既能接收字符串,又能接收OGNL表达式。标记%的被当作OGNL表达式并被执行,没有标记%的被当作普通的字符串。
<struts:label label=”#request.account”></struts:label> //普通字符串,输出#request.account <strtus:label label=”%{#request.account}”</struts:label> //OGNL,输出request的account属性值
‘(字符串常量):以单引号或双引号码括起的字符串,单个字符的字符串常量需用双引号。
<s:property value="'ysy'"/> 说明:不能少单引号,否则会当成根对象的属性名。
,:用于分隔两个以上独立的表达式,整个表达式的值是最后一个子表达式的值.
例如:name, #manager.name
()(数值常量):用单引号括起来的字符。
<s:property value="(123)"/>
{}:用于创建列表,其中元素之间使用逗号分隔。
<s:set name="books" value="#{'book1':'23', 'book2':'55'}" />
in和not in操作符:用于判断一个值是否在集合中。
例如:判断一个对象是否存在List集合中? <s:if test="'foo' in {'foo','bar'}"> muhahaha </s:if> <s:else> boo </s:else>
调用静态方法和静态字段
@class@method() //调用静态方法 @class@field //调用静态字段
说明:class须给出完整的类名,若省略,默认值java.lang.Math
例如:@@max(5,3) //调用java.lang.Math的max方法
在struts.xml中加入(<constant name="struts.OGNL.allowStaticMethodAccess" value="true"></constant> )表示可以访问静态方法。
PS:因为安全问题,访问静态方法不安全,用最新版本,无法获得方法返回值。
调用构造方法
作用:OGNL支持对构造方法的调用,从而创建一个新的对象
例如:new java.util.ArrayList() //须用完整的限定类名
数组和列表索引
数组:array[0],list[0] //得到第1元素 表达式:{‘wang’,‘zhang’,‘li’}[1] //得到结果是第2元素,即list.get(1)
创建列表List
语法:{e1,e2,e3}
示例:<s:select label="label" name="name" list="{'name1','name2','name3'}" value="%{'name2'}" /> 结果:生成了一HTML Select对象,可选的内容为: name1,name2,name3,默认值为:name2。
创建数组[]
例如:new int[]{1,2,3} new int[5] //数组中的元素初始化为0 索引:new int[]{1,2,3}[1]
注意:数组特殊的属性length,OGNL中可访问:array.length。
[N]语法
【提问】访问employee的name属性,应该如何写表达式呢?
【格式】[N].xxx (N是从0开始的整数)
【作用】使用[N].xxx这样的语法来指定从哪一个位置开始向下查找对象的属性,表达式[1].name访问的就是employee对象的name属性。
【注意】在使用[N].xxx语法时,要注意位置序号的含义,它并不是表示“获取栈中索引为N的对象”,而是截取从位置N开始的部分栈。
【示例】栈中有三个对象:Object0,Object1和Object2都有name属性
- 表达式name访问的是Object0的name属性
- [1].name访问的是Object2的name属性,因为[1]是一个包含Object1和Object2的部分栈,而且只有Object2有name属性。
top关键字
top用于获取栈顶的对象,结合[N].xxx语法,就可获取栈中任意位置的对象。
[0].top获取Object0(等同于top), [1].top获取Object1 [2].top获取Object2, [2].top.name访问Object2中的name属性
3,Struts2控制标签
控制标签主要用来完成流程的控制,如条件分支、循环操作,也可以实现对集合的排序和合并。
- if:用于控制选择输出。
- elseif:同if标签结合使用,用来控制选择输出。
- else:同if标签结合使用,用来控制选择输出。
- append:用来将多个集合拼接为一个新的集合。
- generator:为一个字符串解析器,用来将一个字符串解析为一个集合。
- iterator:迭代器,用来迭代输出集合数据。
- merge:用来将多个集合拼接为一个新的集合,同append有所区别。
- sort:用来对集合排序。
- subset:用来截取集合的部分集合,开成新的集合子集合。
3.1,if/elseif/else标签
if/elseif标签属性test:为必填属性,是一个Boolean类型值,决定是否显示if标签内容。
<struts:if test="#parameters.name[0] == 'Kurt'"> Hello, Kurt. </struts:if> <struts:elseif test="#parameters.name[0] == 'Matt'"> Hello, Matt. </struts:elseif> <struts:else> Hello, Other Buddies. </struts:else> <!-- 利用 action 属性判断 --> <struts:if test="name == 'Kurt'"> Hello, Kurt. </struts:if> <struts:elseif test="name == 'Matt'"> Hello, Matt. </struts:elseif> <struts:else> Hello, Other Buddies. </struts:else>
3.2,iterator(迭代标签)
iterator标签主要是对集合进行迭代操作,集合可以使List、Map、Set和数组。
使用iterator标签对集合进行迭代输出时,可以指定如下三个属性:
- value:这是一个可选的属性;用于指定被迭代的集合,被迭代的集合通常都使用OGNL表达式指定。如果没有指定value属性,则使用ValueStack栈顶的集合。
- id:这是一个可选属性;指定了集合里元素的ID,可以用var代替。
- status:这是一个可选的属性,指定迭代时的IteratorStatus实例,通过该实例可以判断当前迭代元素的属性。
<table border="1" width="300"> <s:iterator value="{'Java Web整合开发','轻量级Java EE企业应用实战','Java Web开发经典'}" var="name"> <tr> <td><s:property value="name" /></td> </tr> </s:iterator> </table>
常用的方法有:
- int getCount():返回当前迭代元素的个数。
- int getIndex():返回当前迭代元素的索引值。
- boolean isEven():返回当前迭代元素的索引值是否为偶数。
- boolean isOdd():返回当前迭代元素的索引值是否为奇数。
- boolean isFirst():返回当前迭代元素的是否是第一个元素。
- boolean isLast():返回当前迭代元素的是否是最后一个元素。
使用iterator标签的属性status时,其实例对象包含以上的方法,而且也包含的有对应的属性,如#status.count、#status.even、#status.odd、#status.first等。
<table border="1" width="300"> <tr> <th>序号</th> <th>书名</th> </tr> <!-- 迭代输出List集合 --> <s:iterator value="{'Java Web整合开发','轻量级Java EE企业应用实战','Java Web开发经典'}" var="name" status="st"> <tr <s:if test="#st.odd"> style="background-color:#bbbbbb" </s:if>> <td><s:property value="#st.index+1" /></td> <td><s:property value="name" /></td> </tr> </s:iterator> </table> <table border="1" width="300"> <tr> <th>序号</th> <th>书名</th> </tr> <!-- 迭代输出List集合 --> <s:iterator value="#attr.u" var="u1" status="st"> <tr> <td><s:property value="name" /></td> <td><s:property value="age" /></td> </tr> </s:iterator> </table> <table border="1" width="350"> <tr> <th>序号</th> <th>书名</th> <th>作者</th> </tr> <!-- 对指定的Map对象进行迭代输出,并指定status属性 --> <%-- <s:iterator value="#{'Java Web整合开发':'张三','轻量级Java EE企业应用实战':'李四' ,'Java Web开发经典':'王五'}" id="score" status="st"> --%> <s:iterator value="myMap" var="score" status="st"> <!-- 根据当前被迭代元素的索引是否为奇数来决定是否使用背景色 --> <tr <s:if test="#st.odd"> style="background-color:#bbbbbb" </s:if>> <!-- 输出Map对象里Entry的key --> <td><s:property value="#st.index+1" /></td> <td><s:property /></td> </tr> </s:iterator> </table>
3.3,append标签
用来将多个集合拼接为一个新的集合。目的就是可以将多个集合使用一个<iterator />标签完成迭代。
- 使用append标签时需要指定一个var属性(也可以使用id属性),该属性确定拼接生成的新集合的名字,该新集合被放入StackContext中。
- append标签可以接受多个<s:param>子标签,每个子标签指定一个集合,<s:append>标签负责将<s:param>标签指定的多个集合拼接成一个集合。
<!-- 使用append标签将两个集合拼接成新的集合, 新集合的名字是newList,新集合放入Stack Context中 --> <s:append var="newList"> <s:param value="{'Java程序设计与项目实训教程', 'JSP程序设计与项目实训教程','Web框架技术(Struts2+Hibernate+Spring3)教程'}" /> <s:param value="{'Java程序设计', 'JSP程序设计','SSH技术'}" /> </s:append> <table border="1" width="260"> <!-- 使用iterator迭代newList集合 --> <s:iterator value="#newList" status="st" var="ele"> <tr> <td><s:property value="#st.count" /></td> <td><s:property value="ele" /></td> </tr> </s:iterator> </table> <s:append var="newList"> <s:param value="#{'Java Web整合开发':'张三','轻量级Java EE企业应用实战':'李四' ,'Java Web开发经典':'王五'}" /> <s:param value="#{'http://www.abc.com', 'http://www.def.com'}" /> </s:append> <table border="1" width="280"> <!-- 使用iterator迭代newList集合 --> <s:iterator value="#newList" status="st"> <tr <s:if test="#st.odd"> style="background-color:#bbbbbb" </s:if>> <td><s:property value="key" /></td> <td><s:property value="value" /></td> </tr> </s:iterator> </table>
3.4,merge标签
merge标签和append标签所实现的功能一样,也是将多个集合连接成一个新集合,但是在两个标签生成的新集合中,元素的排序方式有所不同。
3.5,generator标签
用来将指定的字符串按规定的分隔符分解为多个子字符串,生成的多个子字符串可以使用iterator标签输出。
- 可以理解为generator将一个字符串转化成一个Iterator集合。有点类似于String对象的split()方法,但功能更加强大。
- 在该标签的标签体内,整个临时生成的集合将位于ValueStack的顶端,但一旦该标签结束,该集合将被移除ValueStack。
属性:
- count:可选,指定生成集合中元素的总数。
- separator:必选,解析字符串的分隔符。
- val:必选,被解析的字符串。
- converter:可选,指定一个转换器,负责将集合中的每个字符串转换程对象。属性值必须是一个。org.apache.Struts2.until.IteratorGenerator.Converter对象。
- var:可选,如果指定该属性,将生成的Iterator对象放入StackContext中,必须通过#name形式访问;如果不指定,只能在标签内部进行访问。
<!-- 使用generator标签将指定字符串解析成Iterator集合 在generator标签内,得到的List集合位于ValueStack顶端 --> <s:generator val="'疯狂Java讲义 ,轻量级Java EE企业应用实战 ,疯狂iOS讲义'" separator="," var="test"> <!-- 没有指定迭代哪个集合,直接迭代ValueStack顶端的集合 --> </s:generator> <s:iterator status="st" value="#test"> <tr <s:if test="#st.odd"> style="background-color:#bbbbbb" </s:if>> <td><s:property /></td> </tr> </s:iterator>
3.6,subset标签
subset标签用于筛选集合里元素,它使用一个Filter(可以由开发者自定义截取标准),将不合格的元素过滤掉,剩下原集合的一个子集。
在subset标签内,生成的子集合放在ValueStack的栈顶;如果该标签结束后,生成的子集合将被移除ValueStack栈。
属性:
- count:可选属性,指定子集中元素的个数;如果不指定该属性,则默认取得资源集合的全部资源。
- source:可选属性,指定源集合;如果不指定,默认取得ValueStack栈顶的集合。
- start:可选属性,指定子集从源集合的第几个元素开始截取;默认从第一个元素(0)开始。
- decider:可选属性,指定开发者自己决定是否选中该元素;该属性必须指定一个。org.apache.strtuts2.util.SubsetIteratorFilter.Decider对象。
- var:可选属性,如果指定则生成的Iterator对象设置成page范围的属性。
Struts2允许自定义截取标准,如果要实现自定义截取标准,则需要实现一个Decider类,Decider类需要实现SubsetIteratorFilter.Decider接口,并且实现一个boolean decide(Object element)方法,表示如果返回真,则该元素将被选入子集中。
3.7,sort标签
Sort标签根据comparator属性指定的比较器对集合进行排序,并将排序后的迭代器压入值栈的栈顶。在sort标签的内部,你可以使用iterator标签取出栈顶的迭代器对排序后的元素进行迭代。当sort标签结束时,栈顶的迭代器将被删除。
sort标签进行排序时,必须提供自己的排序规则,即实现自己的Comparator,而且Comparator需要实现java.util.Comparator接口。
属性:
- comparator:必选属性,指定进行排序的Comparator对象。
- source:可选属性,指定被排序的集合;如果不指定,则对ValueStack栈顶的集合进行排序。
- var:可选属性,如果指定则生成的Iterator对象设置成page范围的属性。
<!-- 定义一个Comparator实例 --> <s:bean var="mycomparator" name="until.MyComparator" /> <!-- 使用自定义的排序规则对目标集合进行排序 --> <s:sort source="{'Java程序设计与项目实训教程', 'JSP程序设计与项目实训教程','JSP程序设计技术教程','Struts2+Hibernate框架技术教程','Web框架技术(Struts2+Hibernate+Spring3)教程'}" comparator="#mycomparator" var="sortedList" /> <table border="1" width="300"> <!-- 迭代page范围内的sortedList属性 --> <s:iterator status="st" value="#attr.sortedList"> <tr <s:if test="#st.odd"> style="background-color:#bbbbbb"</s:if>> <td><s:property /></td> </tr> </s:iterator> </table>
4,Struts2数据标签
数据标签主要用于提供各种数据访问相关的功能,包含显示一个Action里的属性,生成国际化输出等功能。
4.1,property标签
property标签用于输出值栈中的对象的属性(property)值,使用value属性来指定要输出的对象属性,如果没有指定value属性,那么默认输出栈顶对象。
属性:
- default:可选属性,如果需要输出属性值null,则显示default属性指定的值。
- escape:可选属性,指定是否需要escape HTML代码;默认值为true。
- value:可选属性,指定需要输出的属性值,如果没有指定则输出ValueStack栈顶值。
4.2,set标签
set标签将一个值赋给指定范围内变量,且将一个已有的值复制给新变量,并且可以将新变量放到指定的范围内。
属性:
- scope:可选属性,指定变量范围,可以接受application、session、request、page或action(request范围,并且放入StackContext);默认值action。
- value:可选属性,指定赋给变量的值;如果没有指定,则将ValueStack栈顶的值赋给新变量。
- var:可选属性,如果指定了该属性,则会将该值放入ValueStack中。
<!-- 使用bean标签定义一个JavaBean实例 --> <s:bean name="Bean.Person" var="p"> <s:param name="name" value="'张三'"/> <s:param name="age" value="29"/> </s:bean> 将Stack Context中的p值放入默认范围(action)内。 <br/> <s:set value="#p" var="xxx"/> Stack Context内xxx对象的name属性: <s:property value="#xxx.name"/> <br/> Stack Context内xxx对象的age属性: <s:property value="#xxx.age"/> <br/> <s:property value="#request.xxx.name"/> <br/> <s:property value="#request.xxx.age"/> <hr/> 将Stack Context中的p值放入application范围内。 <br/> <s:set value="#p" var="yyy" scope="application"/> application范围的yyy对象的name属性: <s:property value="#application.yyy.name"/> <br/> application范围的yyy对象的age属性: <s:property value="#application.yyy.age"/> <br/> <hr/> 将Stack Context中的p值放入session范围内。 <br/> <s:set value="#p" var="zzz" scope="session"/> session范围的zzz对象的name属性: <s:property value="#session.zzz.name"/> <br/> session范围的zzz对象的age属性: <s:property value="#session.zzz.age"/>
4.3,push标签
push标签用于把一个值压入值栈(位于栈顶),注意和set标签的区别,set标签是将值放到action上下文中。当push标签结束后,push标签放入值栈中的对象将被删除,换句话说,要访问push标签压入栈中的对象,需要在标签内部去访问。
<h2>使用s:push来将某个值放入ValueStack的栈顶</h2> <!-- 使用bean标签创建一个JavaBean实例, 指定var属性,并将其放入Stack Context中 --> <s:bean name="Bean.Person" var="p"> <s:param name="name" value="'张三'" /> <s:param name="age" value="29" /> </s:bean> <!-- 将Stack Context中的p对象放入ValueStack栈顶--> <s:push value="#p"> <!-- 输出ValueStack栈顶对象的name和age属性 --> ValueStack栈顶对象的name属性:<s:property value="name" /> <br /> ValueStack栈顶对象的age属性:<s:property value="age" /> <br /> </s:push>
4.4,param标签
param标签被用作其他标签的子标签,用于为其他标签提供参数,例如:为bean标签和include标签提供参数。
– name:可选属性,参数名; – value:可选属性,参数值
用法:
(1)<param name=”color”>blue</param>
(2)<param name=”color” value=”blue”/> //blue对象,不存在为null
<param name=”color” value=”’blue’”/> //blue字符串
4.5,bean标签
bean标签用于实例化一个JavaBean对象(必须遵照JavaBean规范),bean标签的标签体内可以包含多个param标签,用于设置Bean的属性(必须有相应的setter方法)。
如果需要使用<param.../>标签获取或传入JavaBean属性值应该为该JavaBean提供对应setter和getter方法。
– name:必选属性,JavaBean的实现类 – var:必选属性,对象名
注意:在bean标签体内,bean标签创建的对象位于ValueStack顶端,一旦该标签结束了,则bean标签创建的对象被移除ValueStack,将无法再次访问,除非指定了var属性,则可通过StackContext来访问该对象。
<body> <!-- 使用bean标签创建一个Person类的实例 --> <s:bean var="p" name="Bean.Person"> <!-- 使用param标签为Person类的实例传入参数 --> <s:param name="name" value="'张三'" /> <s:param name="age" value="29" /> <!-- 因为在bean标签内,Person实例位于ValueStack的栈顶, Person实例的name为:<s:property value="name"/><br/> Person实例的age为:<s:property value="age"/>故可以直接访问lee.Person实例 --> </s:bean> <s:property value="#request.p.name"/> <s:property value="#p.age"/> <br/> <s:bean var="t" name="ex.test" /> <s:property value="#t.test_get('测试')" /> </body>
4.6,action标签
使用action标签可以允许在JSP页面中直接调用Action,需要指定name及namespace;如果指定了executeResult参数的属性值为true,该标签还会把Action的处理结果包含到本页面中。
– var:可选属性,一旦定义该属性,该Action放入Stack Context中 – name:必选属性,决定调用哪个Action – namespace:调用Aciton所在的namespace – executeResult:可选属性,指定是否要将result包含到页面中;默认为false – ignoreContextParams:可选属性,页面请求参数是否传入调用的Action;默认值为false
<body> 下面调用第一个Action,并将结果包含到本页面中。 <br /> <s:action name="tag1" executeResult="true" ignoreContextParams="true" /> <hr /> 下面调用第二个Action,并将结果包含到本页面中。 <br /> 但阻止本页面请求参数传入Action。 <br /> <s:action name="tag2" executeResult="true" ignoreContextParams="true" /> <hr /> 下面调用第三个Action,且并不将结果包含到本页面中。 <br /> <s:action name="tag2" executeResult="flase"> </s:action> 本页面是否可访问? <s:property value="author" /> </body>
4.7,include标签
include标签用来在页面上包含一个JSP页面或者Servlet文件。
– value:必选属性,指定需要包含的JSP页面或Servlet
4.8,date标签
date标签用于格式化输出一个日期,计算指定日期和当前时刻的时间差。
– format:可选属性,如果指定了该属性,根据属性指定的格式来格式化日期 – nice:可选属性,指定是否输出指定日期和当前时刻之间的差值;默认为false – name:必选属性,指定格式化的日期值 – var:可选属性
注意:nice属性和format属性不能同时指定;如果既指定了nice=“true”,也指定了format属性,则会输出时间差。
<body> <s:bean var="now" name="java.util.Date" /> <s:bean var="tom" name="Bean.DateProce" /> nice="false",且指定format="dd/MM/yyyy" <br /> <s:date name="#now" format="dd/MM/yyyy" nice="false" /> <hr /> nice="true",且指定format="dd/MM/yyyy" <br /> <s:date name="#tom" format="dd/MM/yyyy" nice="true" /> <hr /> 指定nice="true" <br /> <s:date name="#tom.getTomorrow()" nice="true" /> <hr /> nice="false",且没有指定format属性 <br /> <s:date name="#now" nice="false" /> <hr /> nice="false",没有指定format属性,指定了var <br /> <s:date name="#now" nice="false" var="abc" /> <hr /> ${requestScope.abc} <s:property value="#abc" /> </body>
4.9,debug标签
主要用于辅助调试,它在页面上生成一个超链接,通过该链接可以查看到ValueStack和StackContext中所有的值信息。
5,Struts2表单标签
Struts的表单标签,可以分为两种:form标签本身和单个表单元素的标签。
所有表单标签处理类都继承了UIBean类,UIBean包含了一些通用属性,这些通用属性分为三种:模板相关属性、JavaScript相关属性、通用属性。
模板相关属性
– templateDir:指定表单所用的模板文件目录 – theme:指定该表单所用的主题 – template:指定表单所用的模板
Struts2提供了四种主题ajax, simple, css_xhtml,xhtml,它默认的是xhtml主题,开发时我们一般都选simple。这4个主题的模板文件放在Struts2的核心类库里(struts2-core.jar包)。
设置主题的方式:
- 通过设定特定UI标签上的theme属性来指定主题。
- 通过设定特定UI标签外围的Form标签的theme属性来指定主题。
- 通过取得page会话范围内以theme为名称的属性来确定主题。
- 通过取得request会话范围内以theme为名称的属性来确定主题。
- 通过取得session会话范围内以theme为名称的属性来确定主题。
- 通过取得application会话范围内以theme为名称的属性来确定主题。
- 通过取得名为struts.ui.theme的常量(默认值是xhtml)来确定主题,该常量可以在struts.properties文件或者struts.xml文件中确定。如:<constantname="struts.ui.theme" value="simple" />
JavaScript相关属性
通用属性
Struts2中大部分表单标签和HTML表单元素一一对应,<form.../>标签不仅生成<form>标记,还会生成<table>标记。
对于表单标签而言,name和value属性之间存在一个特殊的关系:
- 因为每个表单元素会被映射成Action属性,所以如果某个表单对应的Action已经被实例化(表单被提交)、且属性有值时,则该Action对应表单里的元素会显示出该属性的值,这个值作为表单标签的value值。
- name属性设置表单元素的名字,表单元素的名字实际上封装着一个请求参数,而请求参数是被封装到Action属性的值,所以在使用Struts2的标签库时,无须指定value属性,Struts2标签会自动处理。
5.1,select标签
select标签用于生成一个下拉列表框,使用该标签必须指定list属性,系统会使用list属性指定的集合来生成下拉列表框的选项。
属性:
− list:要迭代的集合,使用集合中的元素来设置各个选项,如果list的属性为Map则Map的key成为选项的value,Map的value会成为选项的内容 − listKey:指定集合对象中的哪个属性作为选项的value − listValue:指定集合对象中的哪个属性作为选项的内容 − headerKey:设置当用户选择了header选项时提交的value,如果使用该属性,不能为该属性设置空值 − headerValue:显示在页面中header选项内容 − emptyOption:是否在header选项后面添加一个空选项 − multiple:是否多选 − size:显示的选项个数
<body> <h3>使用s:select生成下拉选择框</h3> <s:form> <!-- 使用简单集合来生成下拉选择框 --> <s:select name="a" label="请选择您喜欢的图书" labelposition="top" multiple="true" list="{'Java程序设计与项目实训教程', 'JSP程序设计与项目实训教程','Web框架技术(Struts2+Hibernate+Spring3)教程'}" /> <!-- 使用简单Map对象来生成下拉选择框 --> <s:select name="b" label="请选择您想选择出版日期" labelposition="top" list="#{'疯狂Java讲义':'2008年9月', '轻量级Java EE企业应用实战':'2008月12月', 'SSH程序设计':'2014年1月'}" /> <!-- 创建一个JavaBean实例 --> <s:bean name="service.BookService" var="bs" /> <!-- 使用集合里放多个JavaBean实例来生成下拉选择框 --> <s:select name="c" label="请选择您喜欢的图书" labelposition="top" multiple="true" list="#bs.books" listKey="author" listValue="name" /> </s:form> </body>
5.2,optgroup标签
optgroup标签用于生成一个下拉列表框的选项组。
该标签必须放在<s:select.../>中使用,一个下拉列表可以包含多个选项组,使用optgroup标签时,一样需要指定list、listKey和listValue等属性。
optgroup标签可以指定label属性,而该label属性时选项组的组名,浏览者无法选中选项组的label。
<body> <h3>使用s:optgroup生成下拉选择框的选项组</h3> <s:form> <!-- 直接使用Map为列表框生成选项 --> <s:select label="选择您喜欢的图书" name="book" size="7" list="#{'Java程序设计与项目实训教程', 'JSP程序设计与项目实训教程','Web框架技术(Struts2+Hibernate+Spring3)教程'}" listKey="value" listValue="key"> <!-- 使用Map对象来生成选择框的选项组 --> <s:optgroup label="Rod Johnson" list="#{'Expert One-on-One J2EE Design and Development':'Johnson'}" listKey="value" listValue="key" /> <s:optgroup label="David Flanagan" list="#{'JavaScript: The Definitive Guide':'David'}" listKey="value" listValue="key" /> </s:select> </s:form> </body>
5.3,updownselect标签
类似select标签,区别是该标签生成的列表可以上下移动选项。另外与select相同都要指定list、listkey和listvalue等属性。
其他属性:
– allowMoveUp:是否显示“上移”按钮,默认为true – allowMoveDown:是否显示“下移”按钮,默认为true – allowSelectAll:是否显示“全选”按钮,默认为true – moveUpLabel:设置“上移”按钮文本,默认是“^” – moveDownLabel:设置“下移”按钮文本,默认是“v” – selectAllLabel:设置“全选”按钮文本,默认是“*”
<body> <h3>使用s:updownselect生成可上下移动选项的下拉选择框</h3> <s:form> <!-- 使用简单集合来生成可上下移动选项的下拉选择框 --> <s:updownselect name="a" label="请选择您喜欢的图书" labelposition="left" moveUpLabel="向上移动" list="{'Java程序设计与项目实训教程', 'JSP程序设计与项目实训教程','Web框架技术(Struts2+Hibernate+Spring3)教程'}" /> <!-- 使用简单Map对象来生成可上下移动选项的下拉选择框 且使用emptyOption="true"增加一个空选项--> <s:updownselect name="b" label="请选择您想选择出版日期" labelposition="top" moveDownLabel="向下移动" list="#{'疯狂Java讲义':'2008年9月' ,'轻量级Java EE企业应用实战':'2008月12月' ,'疯狂iOS讲义':'2014年1月'}" listKey="key" emptyOption="true" listValue="value" /> <s:bean name="service.BookService" var="bs" /> <!-- 使用集合里放多个JavaBean实例来可上下移动选项的生成下拉选择框 --> <s:updownselect name="c" label="请选择您喜欢的图书的作者" labelposition="top" selectAllLabel="全部选择" multiple="true" list="#bs.books" listKey="author" listValue="name" /> </s:form> </body>
5.4,doubleselet标签
级联列表,当选择第一个列表时,第二个列表框的内容会随之改变。
属性:
因为两个都是下拉列表,因此需要指定两个下拉列表框的选项 – list:指定输出第一个下拉列表框中选项集合 – listKey:第一个下拉列表框的值 – listValue:第一个下拉列表框的标签 – doubleList:指定输出第二个下拉列表框中选项集合 – doubleListKey:第二个下拉列表框的值 – doubleListValue:第二个下拉列表框的标签 – doubleName:第二个下拉列表框的name属性
<s:form > <s:doubleselect label="请选择您喜欢的图书" name="author" list="{'张三', '李四'}" doubleList="top == '张三' ? {'轻量级Java EE企业应用实战', 'J2EE','SSH'}: {'JavaScript: The Definitive Guide'}" doubleName="book"/> </s:form>
注意:使用doubleselect标签时,必须放在<s:form.../>标签中使用;默认情况下,第一个下拉列表框只支持两项,如果要包含更多的值list和doubleList就不能直接设定;可以采用一种迂回方式来实现,首先定义一个Map对象,该Map对象的value都是集合,这样就能以Map对象的多个key创建第一个下拉列表框的列表项,而每个key对应的集合则用于创建第二个下来列表框的列表项。
<!-- 创建一个复杂的Map对象,key为普通字符串,value为集合 --> <s:set var="bs" value="#{'张三':{'轻量级Java EE企业应用实战', 'J2EE','SSH'}, 'David': {'JavaScript: The Definitive Guide'}, 'Johnson': {'Expert One-on-One J2EE Design and Development'}}"/> <!-- 使用Map对象来生成级联列表框 --> <s:form action="x"> <s:doubleselect label="请选择您喜欢的图书" size="3" name="author" list="#bs.keySet()" doubleList="#bs[top]" doubleSize="3" doubleName="book"/> </s:form>
keySet:将map集合中所有的键存入到Set集合,因为Set具备迭代器。 所有可用迭代方式取出所有的键,再根据get方法,获取每一个键对应的值。
5.5,optiontransferselect标签
联动列表,optiontransferselect会生成两个列表选择框,并生成系列的按钮用于控制各选项在两个下拉列表之间的移动、升降等;当提交表单时,两个列表框对应的请求参数都会提交。
属性:
– addAllToLeftLabel:设置全部移动到左边按钮的文本 – addAllToRightLabel:设置全部移动到右边按钮的文本 – addToLeftLabel:设置左移动按钮的文本 – addToRightLabel:设置右移动按钮的文本 – allowAddAllToLeft:设置是否出现全部移动到左边的按钮 – allowAddAllToRight:设置是否出现全部移动到右边的按钮 – allowAddToLeft:设置是否出现全部移动到左边的按钮 – allowAddToRight:设置是否出现全部移动到右边的按钮 – leftTitle:设置左边列表的标题 – rightTitle:设置右边列表的标题 – allowSelectAll:设置全选按钮 – list:第一个下拉选择框的集合 – listKey:第一个下拉选择框的value属性 – listValue:第一个下拉选择框的label属性 – name:设置第一个下拉选择框的name属性 – value:设置第一个下拉选择框的value属性 – multiple:设置第一个下拉选择框是否允许多选 – doubleList:第二个下拉选择框的集合,必选属性 – doubleListKey:第二个下拉选择框的value属性 – doubleListValue:第二个下拉选择框的label属性 – doubleName:设置第二个下拉选择框的name属性,必选 – doubleValue:设置第二个下拉选择框的value属性,必选 – doubleMultiple:设置第二个下拉选择框是否允许多选
<body> <h3>使用s:optiontransferselect来生成可移动列表项的下拉列表框</h3> <s:form> <!-- 使用简单集合对象来生成可移动的下拉列表框 --> <s:optiontransferselect label="请选择你喜欢的图书" name="cnbook" leftTitle="中文图书:" rightTitle="外文图书" list="{'Java程序设计与项目实训教程', 'JSP程序设计与项目实训教程','Web框架技术(Struts2+Hibernate+Spring3)教程'}" multiple="true" addToLeftLabel="向左移动" selectAllLabel="全部选择" addAllToRightLabel="全部右移" headerKey="cnKey" headerValue="--- 选择中文图书 ---" emptyOption="true" doubleList="{'Expert One-on-One J2EE Design and Development', 'JavaScript: The Definitive Guide'}" doubleName="enBook" doubleHeaderKey="enKey" doubleHeaderValue="--- 选择外文图书 ---" doubleEmptyOption="true" doubleMultiple="true" /> </s:form> </body>
5.6,radio、checkbox、checkboxlist标签
checkbox属性:
− id和name:指的是该标签的标识id和标识名。 − value:指是否选中,其值只能为True或False,相当于传统checkbox中的checked。 − fieldValue:相当于传统checkbox中的value值。 − label:对于该checkbox显示在页面上方框后面的描述。
<body> <h3>使用s:radio生成多个单选框</h3> <s:form> <!-- 使用简单集合来生成多个单选框 --> <s:radio name="a" label="请选择您喜欢的图书" labelposition="top" list="{'Java程序设计与项目实训教程', 'JSP程序设计与项目实训教程','Web框架技术(Struts2+Hibernate+Spring3)教程'}" /> <!-- 使用简单Map对象来生成多个单选框 --> <s:radio name="b" label="请选择您想选择出版日期" labelposition="top" list="#{'疯狂Java讲义':'2008年9月' ,'轻量级Java EE企业应用实战':'2008月12月' ,'SSH程序设计':'2014年1月'}" listKey="key" listValue="value" /> <!-- 创建一个JavaBean实例 --> <s:bean name="service.BookService" var="bs" /> <!-- 使用集合里放多个JavaBean实例来生成多个单选框 --> <s:radio name="c" label="请选择您喜欢的图书" labelposition="top" list="#bs.books" listKey="author" listValue="name" /> </s:form> </body>
<body> <h3>使用s:checkbox生成多个复选框</h3> <s:form> <!-- 使用简单集合来生成多个单选框 --> <s:iterator value="#{'Java Web整合开发':'张三','轻量级Java EE企业应用实战':'李四' ,'Java Web开发经典':'王五'}" var="score" status="st"> <s:checkbox name="a" value="false" fieldValue="%{key}" label="%{value}" labelposition="right" /> </s:iterator> </s:form> </body>
<body> <h3>使用s:checkboxlist生成多个复选框</h3> <s:form> <!-- 使用简单集合来生成多个复选框 --> <s:checkboxlist name="a" label="请选择您喜欢的图书" labelposition="top" list="{'Java程序设计与项目实训教程', 'JSP程序设计与项目实训教程','Web框架技术(Struts2+Hibernate+Spring3)教程'}" /> <s:checkboxlist name="b" label="请选择您想选择出版日期" labelposition="top" list="#{'疯狂Java讲义':'2008年9月' ,'轻量级Java EE企业应用实战':'2008月12月' ,'疯狂iOS讲义':'2014年1月'}" listKey="key" listValue="value" /> <!-- 创建一个JavaBean对象,并将其放入Stack Context中 --> <s:bean name="service.BookService" var="bs" /> <!-- 使用集合里放多个JavaBean实例来生成多个复选框 使用集合元素里name属性作为复选框的标签 使用集合元素里author属性作为复选框的value--> <s:checkboxlist name="b" label="请选择您喜欢的图书" labelposition="top" list="#bs.books" listKey="author" listValue="name" /> </s:form> </body>
5.7,hidden标签
hidden标签输出一个HTML隐藏表单元素,等价于HTML代码:<input type=“hidden”…/>。
5.8,submit标签
submit标签输出一个提交按钮。 submit标签和form标签一起使用可以提供异步表单提交功能。
submit标签可以输出以下三种类型的提交按钮: − input:等价于HTML代码<input type=“submit”…> − image:等价于HTML代码<input type=“image”…> − button:等价于HTML代码<input type=“submit”…>
struts2提供的一种特性,即使用一些预定义的前缀来命名一个按钮,通过按钮的名字来改变执行的行为。Struts2定义了4个前缀,如下:
− method:使用method前缀,来取代action默认的execute()方法的执行 − action:使用action前缀,取代form标签指定的action,将请求导向到另外的action进行处理。 − redirect:使用redirect前缀将请求重定向到其他的URL,甚至可以是Web应用程序外部的URL。 − redirection-action:使用redirect-action前缀将请求重定向到其他的action。在内部,struts2使用ServletRedirectResult来执行这个任务。
使用formaction属性可以实现取代form标签指定的action
<s:form action="userManager"> <s:textfield label="用户名" name="username" /> <s:password label="密码" name="password" /> <s:submit value="登录" name="method:login" /> <s:submit value="注册" name="method:regist" /> </s:form>
5.9,reset标签
reset标签输出一个重置按钮。
<s:reset value=“重置” /> <s:reset type=“button” label=“重置” /> 如果是类型为input的重置按钮,则只能通过value属性来设置重置按钮上的文本。
5.10,lablel标签
Xhtml主题下的label标签输出两个HTML的label标签(simple主题下的label标签只输出一个HTML label标签),分别位于一行的两列,左边的label标签起提示作用,右列的label标签用于显示只读的action属性数据。
<body> <s:bean name="Bean.Person" var="p"> <s:param name="name" value="'张三'" /> <s:param name="age" value="19" /> </s:bean> <s:label label="姓名" name="#p.name" /> </body>
5.11,token标签
防止重复提交表单;如果需要该标签起作用,则应该在Struts2的配置启动TokenInterceptor拦截器或TokenSessionStoreInterceptor拦截器。
原理:在表单中增加一个隐藏域,每次加载该页面时,该隐藏域的值都不相同。而TokenInterceptor拦截器则拦截所有用户请求,如果两次请求时该token对应的隐藏域的值相同(前一次提交时token隐藏域的值保存在session里),则阻止表单提交。
<body> <h3>使用s:token防止重复提交</h3> <s:form action="pro"> <!-- 普通表单域 --> <s:textfield name="book" label="书名" /> <!-- 用于防刷新的token --> <s:token /> <s:submit value="提交" /> </s:form> </body>
6,非表单标签
6.1,component标签
使用component标签可以自定义组件,当需要多次使用某些代码段是,就可以自定义一个组件在页面中使用component标签多次调用。
属性:
− theme属性:该属性用来指定自定义组件所使用的主题,默认值为xhtml。 − templateDir属性:该属性用来指定自定义组件使用的主题目录,默认值为template。 − template属性:该属性用来指定自定义组件所使用的模板文件,自定义模板文件可以采用JSP、FreeMarker和Velocity这3中技术编写代码。
<body> <s:set value="#p" var="p_l" /> <!--使用component标签调用模版--> <s:component template="myTemplate.jsp"> <s:param name="songList" value="{'中国人','真心英雄','青花瓷','传奇','北京欢迎你'}" /> </s:component> <hr /> 使用自定义主题,自定义主题目录 <br /> 使用myAnotherTemplate.jsp作为视图组件 <s:component templateDir="/myTemplateDir" theme="myTheme" template="myAnotherTemplate.jsp"> <s:param name="songList" value="{'中国人','真心英雄','青花瓷','传奇','北京欢迎你'}" /> </s:component> </body>
6.2,actionerror、actionmessage、fielderror标签
actionerror和actionmessage用法一样,都是负责输出Action对象封装的信息。
区别:actionerror标签负责输出Action对象的getActionError()方法的返回值,而actionmessage负责输出Action对象的getActionMessages()方法的返回值。
<head> <title>使用s:actionerror和s:actionmessage标签生成错误提示</title> <s:head/> </head> <body> <s:action name="msgdemo" executeResult="true"/> </body>