struts2 页面遍历显示集合

一,基础了解

Struts2支持以下几种表达式语言:

1. OGNL(Object-Graph Navigation Language),可以方便地操作对象属性的开源表达式语言;

2. JSTL(JSP Standard Tag Library),JSP 2.0集成的标准的表达式语言;

3. Groovy,基于Java平台的动态语言,它具有时下比较流行的动态语言(如Python、Ruby和Smarttalk等)的一些起特性;

4. Velocity,严格来说不是表达式语言,它是一种基于Java的模板匹配引擎,具说其性能要比JSP好。

Struts 2默认的表达式语言是OGNL,原因是它相对其它表达式语言具有下面几大优势:

1. 支持对象方法调用,如xxx.doSomeSpecial();

2. 支持类静态的方法调用和值访问,表达式的格式为@[类全名(包括包路径)]@[方法名 | 值名],例如:@java.lang.String@format('foo %s', 'bar')或@tutorial.MyConstant@APP_NAME;

3. 支持赋值操作和表达式串联,如price=100, discount=0.8, calculatePrice(),这个表达式会返回80;

4. 访问OGNL上下文(OGNL context)和ActionContext;

5. 操作集合对象。

关于struts中logic:iterate标签使用的详细说明

logic:iterate

logic:iterate标签用来迭代集合,您可以使用如下方式来为这个标签指定其要叠代的集合:

使用一个运行时表达式,这个表达式的值是一个集合。

用name属性引用一个JSP Bean,这个JSP Bean本身就是一个集合(或者干脆直接引用集合类.)。

用name属性引用一个JSP Bean,这个JSP Bean的一个属性是一个集合,这时可以联合使用property来指定这个集合。

上面所提到的集合可以是:

对象类型或原子类型的数组(Array)。

java.util.Collection的实现,包括ArrayList,Vector。

java.util.Enumeration的实现。

java.util.Iterator的实现。

java.util.Map的实现,包括HashMap,Hashtable和TreeMap。

如果您叠代的集合中含有null的值,这时需要采取一定的措施,因为这时logic:iterate不会在page作用域中创建对象。一般是使用<logic:present>标签或<logic:notPresent>标签来判断一下。

iterate标签的常用属性如下:

● id:指定页面范围的jsp变量的名称,该变量存储每次迭代的当前集合元素的引用.也就是说,id属性的值时可以任意写的,他存储了迭代当前集合元素的值.不过要保证<bean:write>标签的 name属性的值和iterate标签的id值一致.如下图三所示.

● name:指定包含要迭代的集合对象的名称,如果还指定了property属性,将调用对象中该属性定义的一个字段的值获取方法,以返回一个要迭代的集合.也就是说,在没有property属性的时候,name属性指的是一个集合,而在有property属性的时候,name属性指的一般是一个form-bean,当然你也可以用jsp:userBean标签指定一个bean,而property属性指的是这个form-bean(bean)的一个集合类.

OGNL表达式

  OGNL,全称为Object-Graph Navigation Language,它是一个功能强大的表达式语言,用来获取和设置Java对象的属性,它旨在提供一个更高的更抽象的层次来对Java对象图进行导航。

  OGNL表达式的基本单位是"导航链",一般导航链由如下几个部分组成:

  1. 属性名称(property)

  2. 方法调用(method invoke)

  3. 数组元素

  所有的OGNL表达式都基于当前对象的上下文来完成求值运算,链的前面部分的结果将作为后面求值的上下文。例如:names[0].length()。

对于使用上下文的OGNL,若不指定从哪一个对象中查找"name"属性,则OGNL直接从根对象(root)查找,若指定查找对象(使用'#'号指定,如#person1),则从指定的对象中查找,若指定对象不在上下文中则会抛出异常,换句话说就是是#person1.name形式指定查找对象则必须要保证指定对象在上下文环境中。

 使用OGNL调用方法也十分简单,对于成员方法调用,只需要给出方法的名称+(),若有参数,直接写在括号内,与一般调用Java方法一致。对于静态方法的调用,需要使用如下格式:@ClassName@method,对于静态变量需要使用如下格式:@ClassName@field。

 OGNL不仅可以操作集合对象,还可以创建集合对象,对集合操作与对属性的操作没什么不同,需要注意的是OGNL认为List与Array是一样的。使用OGNL创建List集合时使用{},创建Map对象时使用#{}。

OGNL可以对集合进行过滤与投影操作,过滤的语法为collection.{? expression},其中使用"#this"表示集合当前对象(可以与for-each循环比较)。投影的语法为collection.{expression}。投影和过滤可以看做是数据库中对表取列和取行的操作。

 平时使用Struts2标签时会出现一些很奇特的问题,对于OGNL不了解的人可能对问题的出现无能为力或者就算解决了问题也不知道是如何解决的。下面总结一些使用Struts2标签容易出现的困惑:

问题一:#,%{},$符号

  在Struts2标签属性中经常会出现"#"或者"%{}"的符号出现,通过上面OGNL表达式基础的介绍,知道了OGNL上下文中有且仅有一个根对象。Struts2为我们定义了许多明明对象,他们分别是"ValueStack","Parameters","Session","Request", "Appliction","Attr",其中"ValueStack"被设置为上下文的根对象。访问非根对象必须加上"#"号,这就是出现"#"的原因。Struts2中的标的处理类,并不是所有都将标签的属性作为OGNL表达式来看待,有时候我们需要设置动态地值,则必须告诉标签的处理类该字符串按照OGNL表达式来处理,%{}符号的作用就是告诉标签的处理类将它包含的字符串按照OGNL表达式处理。 "$"符号用于XML文件中用于获取动态值,与%{}作用类似。

问题二:%{}符号的影响

  Struts2的标签几十几百个,要记住哪一个标签的处理类将标签的属性作为OGNL表达式是一件很困难的事情,在不清楚处理类的处理方式时怎么办,%{}对于标签处理类来说,若处理类将属性值作为普通字符串则%{}符号包含的字符串当做OGNL表达式,若处理类将属性值作为OGNL表达式来处理,则直接忽略%{}符号。换句话说,不清楚处理方式的话,可以都使用%{}符号。

问题三:标签是如何获得数据

下面是ValueStack的官方描述:

ValueStack allows multiple beans to be pushed in and dynamic EL expressions to be evaluated against it. When evaluating an expression, the stack will be searched down the stack, from the latest objects pushed in to the earliest, looking for a bean with a getter or setter for the given property or a method of the given name (depending on the expression being evaluated).

大致意思:ValueStack允许保存多个bean(也就是Action),并且可以使用表达式语言获得他们。当评估一个表达式,ValueStack将会从栈顶到栈底的方向被搜索一遍,对于给定的属性名称寻找bean的getter或setter方法或寻找给定的方法。

每当一个请求到达Action时,Struts2会将Action对象推入ValueStack中。

可以看到标签取值与用Java代码取值的结果相同,明显标签的取值方式更简练简洁。OGNL表达式"username"表示了从根对象ValueStack中取出属性username的值。它会从栈顶到栈底遍历ValueStack,直到找某一个Action中的"username"属性。

二、方法示例

<s:iterator />可以遍历数据栈里面的任何数组,集合等等

在使用这个标签的时候有三个属性值得我们关注

1. value属性:可选的属性,value属性是指一个被迭代的集合,使用ognl表达式指定,如果为空的话默认就是ValueStack栈顶的集合.

2.id属性:可选属性, 是指集合元素的id

3.status属性:可选属性,该属性在迭代时会产生一个IteratorStatus对象,该对象可以判断当前元素的位置,包含了以下属性方法:

int getCount(); 迭代元素个数

int getIndex(); 迭代元素当前索引

boolean getFirst(); 是否为第一个

boolean getEven(); 是否为偶

boolean getLast(); 是否最后一个

bolean getOdd(); 是否为奇

由于iteratorstatus对象并不是ognl的根对象因此访问需要加上 #访问如下例子:

<s:iterator value=”{’dd’,'bb’,'cc’}” status=”st”>

<s:if test=”#st.odd”>

<s:property value=”#st.index”/>

</s:if>

</s:iterator>

iterator也可以迭代map对象,map对象中有几对key-value 就迭代几次,分别使用

<s:property value=”key”/>

<s:property value=”value”/>

iterator也可以迭代简单的数组集合

<s:iterator value="collection1" status="status">

<s:property value="collection1[#status.index][0]"/>

<s:property value="collection1[#status.index][1]"/>

</s:iterator>

说明:[#status.index][?]" ,指示遍历数组指定的脚标元素,

如果你不知道数组的长度呢?

//以下是遍历数组每一个元素

<s:iterator value="total" status="stuts">

<s:iterator value="total[#stuts.index]" >

<s:property/><br>

</s:iterator>

</s:iterator>

//直接使用<s:property/>也可以打印出每一个数组内容

***********iterator的value******************

1.如果需要引用valueStack中的值,需要使用这样的形式。

<s:iterator value="#userList" /> //userList在action部分被保存在Request中,所以使用#加属性名来引用值。

2.如果集合的值是通过action的方法,假设我们的action中有一个getListMenu方法,返回一个List集合。

我们可以使用如下的形式来引用这个集合,并用s:iterator来输出。

<s:iterator value="listMenu" />

3.iterator的value使用定义好的方式,如:

<s:iterator value="{1,2,3,4}" /> //这样跌代输出的值就是1.2.3.4这四个值。

**************iterator的各个对象属性输出********************************

iterator中输出具体值,如果,在上面我们的list中的对象,有两个属性,都是String类型,一个是name,一个是url

1. <s:property value="name" /> //这样我们将可以输出跌代对象的name属性值。

2. 如果我们希望使用<s:url />来将跳转过后的url进行处理,该如何来做?

<s:url value="%{url}"/> //%{}ognl的表达式,这样的值能够将url的值进行<s:url/>的处理.实际上就是转为绝对路径。这样,我们就可以对付一些因跳转换产生的路径问题.原因:因为<s:iteratotr />以后,当前的对象应该就在ValueStack顶部了,这样当时的url实际上就是对象的url属性了

C:使用ognl输出对应的值。

<s:textfield name="loginName" value="%{#request.loginNames}"/>

使用此表达式,会生成一个文本框,并且,如果request.attribute中有loginNames属性,将会做为些文本框的默认值。

如果只使用#request.loginNames在struts2的标签内部,是不会显示任何值的,注意外面加上的%{}附号,才会被正常的使用。

如果希望如EL语言一样直接输出文件,如在一个<a></a>之间的innerHTML文本为#request.loginNames的值,我们只要使用:<s:property value="#request.loginNames" />使可以正常使用!

注意:

1.${}是EL语言的 %{}这样的形式是ognl表达式语言的,在struts2的标签内部,使用%{}这样的形式,在标签外部可以使用${}EL语言的方式。如果在struts2的标签内部使用${}这样的方式,会出现以下的错误提示:

According to TLD or attribute directive in tag file, attribute value does not accept any expressions

2. 很多时候,我们使用struts2的一些标签,属性是需要接受集合的,如果集合是保存在 request,session,或者是值栈(非根对象的栈顶),可以使用#变量名的方式,如果获取的值是在Action中通过特定的方法来获取,就需要使用如 value="userList"这样的方式,只是去掉了前面的#。

以下几个简单的例子:

<s:iterator/> 标签有3个属性:

value:被迭代的集合

id :指定集合里面的元素的id

status 迭代元素的索引

1:jsp页面定义元素写法 数组或list

1. <s:iterator value="{'1','2','3','4','5'}" id='number'>

2. <s:property value='number'/>A

3. </s:iterator>

打印结果为: 1A2A3A4A5A

2:索引的用法

如果指定了status,每次的迭代数据都有IteratorStatus的实例,它有以下几个方法

int getCount()返回当前迭代了几个元素

int getIndex()返回当前元素索引

boolean isEven()当然的索引是否偶数

boolean isFirst()当前是否第一个元素

boolean isLast()

boolean isOdd()当前元素索引是否奇数

<s:iterator value="{'a','b','c'}" id='char' status='st'>

<s:if test="#st.Even">

现在的索引是奇数为:<s:property value='#st.index'/>

</s:if>

当前元素值:<s:property value='char'/>

</s:iterator>

3:遍历map

value可以直接定义为:

1. value="#{"1":"a","2":"b"}"

每个元素以都逗号隔开。元素之间的key和value 冒号隔开

value也可以是数据栈里面的java.util.Map对象

遍历写法如下:

<s:iterator value="map" id="id" status="st">

key : <s:property value='key'/>

value:<s:property vlaue='value'/>

</s:iterator>

当然key 和value 都可以使java 的 Object

3:遍历数据栈.简单的List类,

List<Attr>

class Attr{String attrName;String getAttrName(){return "123";}}

1. <s:iterator value="label" id="id">

2. <s:property value="#id.attrName" />

3. </s:iterator>

当然value 还可以写成 value="%{label}" label可以有.操作

label的属性List 可以写成value="%{label.list}" 相当于:getLabel().getList();

4:遍历2个list;

List<AttrName> attrN {color,size,style}

List<AttrValue> attrV {red,20,gay}

这2个list的元素是一一对应的,一个attrN对应一个attrV

<s:iterator value="%{attrN }" id="id" status="status">

index is : <s:property value='status.index'/>

attrName is : <s:property value='id'/> or <s:property value='%{id}'/>

attrName is : <s:property value='%{attrV[#status.index]}'/>

</s:iterator>

图中的persons列表是在ListAction中填充的,在这里只是简单的加入了三个Person对象,在实际的应用中这些数据应该取自数据库。具体的代码如下:

public ActionForward execute(ActionMapping mapping,ActionForm form, HttpServletRequest request, HttpServletResponse response) {

ListForm listForm = (ListForm) form;

List<Person> persons = new ArrayList<Person>();

Person person1 = new Person();

person1.setId("00001");

person1.setName("赵辰");

Person person2 = new Person();

person2.setId("00002");

person2.setName("李为芳");

Person person3 = new Person();

person3.setId("00003");

person3.setName("王微");

persons.add(person1);

persons.add(person2);

persons.add(person3);

listForm.setPersons(persons);

return mapping.findForward("success");

标签输出的结果为:

00001-->赵辰

00002-->李为芳

00003-->王微

在struts中,读取数据库中的多条数据然后显示到jsp页面上可以用如下的方法去做:

1.在Form中定义一个ArrayList import java.util.ArrayList;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts.action.ActionErrors;

import org.apache.struts.action.ActionForm;

import org.apache.struts.action.ActionMapping;

public class AlloperationForm extends ActionForm {

private ArrayList list;

public ActionErrors validate( ActionMapping mapping, HttpServletRequest request) { }

public void reset(ActionMapping mapping, HttpServletRequest request) {} public ArrayList getList() { return list; } public void setList(ArrayList list) { this.list = list; }}

2.在Action中调用一个返回游标的存储过程,得到所有的记录,找把它封装成一个Bean. public class AlloperationAction extends Action {public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { AlloperationForm operationForm =(AlloperationForm)form;

Connection conn=ConnectDataBase.connection();

String callFunction="{?=call alloperation.getalloperation}";

ResultSet rs = null;

ArrayList alist=new ArrayList(); try { CallableStatement stmt=conn.prepareCall(callFunction);

stmt.registerOutParameter(1,OracleTypes.CURSOR);

stmt.execute();

rs = ((OracleCallableStatement)stmt).getCursor(1);

while(rs.next())

{

String operationName=rs.getString(1);

String operationType=rs.getString(2);

String charge=rs.getString(3);

String charegeType=rs.getString(4);

System.out.println("operationName"+operationName);

System.out.println("operationType"+operationType);

System.out.println("charge"+charge);

System.out.println("chargeType"+charegeType);

AllOperationBean operationBean=new AllOperationBean

(operationName,operationType,charge,charegeType);

alist.add(operationBean);

}

conn.close();

operationForm.setList(alist);

} catch (SQLException e) { e.printStackTrace();

}

return mapping.getInputForward();

}

定义的bean:

在jsp页面中用标签调用代码如下图:其中alloperationFormation是在struts配置文件中定义的form-bean的名称.

 

通过上述步骤就可以在jsp页面中显示出多条记录了..

<logic:iterate> 是Logic 标签库中最复杂的标签,也是用途最广的一个标签,它能够在一个循环中遍历数组、Collection、Enumeration、Iterator 或 Map 中的所有元素。

1. 遍历集合

<logic:iterate> 的 name 属性指定需要进行遍历的集合对象, 它每次从集合中检索出一个元素, 然后把它放在page 范围内, 并以id 属性指定的字符串来命名这个元素, 例如:

<%

Vector animals = new Vector();

animals.addElement("Dog");

animals.addElement("Cat");

animals.addElement("Bird");

animals.addElement("Chick");

request.setAttribute("Animals", animals);

%>

<logic:iterate id="element" name="Animals">

<bean:write name="element"/><br>

</logic:iterate>

以上代码先定义了一个Vector 类型的集合变量 Animals, 它存放在request 范围内. 接下来<logic:iterate> 标签在一个循环中遍历Animals 集合(这个集合名就是在标签中的name 属性的值)中所有元素, 每次检索到一个元素, 就把它命名为"element"(标签id 属性的值), 并存放在page 范围内.

在<logic:iterate> 中, 还嵌套了一个<bean:write>标签, 它用于输出每个元素的内容. 以上代码的输出内容如下:

Dog

Cat

Bird

Chick

length 属性指定需要遍历的元素的数目, 如果没有设置length 属性, 就遍历集合中的所有元素.

offset 属性指定开始遍历的起始位置, 默认值为 "0" , 表示从集合的第一个元素开始遍历.

scope:可以指定指定作用范围如:scope=”request”或session.

indexId 属性定义一个代表当前遍历元素序号的变量, 这个变量被存放在 page 范围内, 可以被标签主体的<bean:write> 标签访问. 例如:

<logic:iterate

id="element" // 指定输出元素的名 与 <bean:write> 中name 属性一致

indexId="index" // 遍历元素序号的变量, 这个变量放在page 范围内

name="Animals" // request 中的集合名, 从中取循环取出元素

offset="1" // 从集合的第 2 条记录开始取数

length="2"> // 取出 2 个元素

<bean:write name="index"/>. // 输出每个元素的序号, 与indexId 的属性一致

<bean:write name="element"/><br> // 输出每个元素的内容, 与id 的属性一致

</logic:iterate>

2. 遍历Map

<logic:iterate> 标签还可以遍历HashMap 中的元素, 例如:

<%

HashMap months = new HashMap();

months.put("Jan","January");

months.put("Feb","February");

months.put("Mar","March");

request.setAttribute("month", months);

%>

<logic:iterate id="element" indexId="ind" name="months">

<bean:write name="ind"/>. // 序号

<bean:write name="element" property="key"/>: // 键名

<bean:write name="element" property="value"/> // 键值

</logic:iterate>

以上代码先定义一个名为"months" 的HashMap, 存放在request 范围内. 接下来在<logic:iterate> 标签遍历months 对象的每一个元素, 每一个元素包含一对 key/value . 在<logic:iterate> 标签主体中包含三个<bean:write> 标签, 分别输出每个元素的序号、key 和 value. 以上代码的输出内容如下:

0.Mar: March

1.Feb: February

2.Jan: January

如果HashMap 中的每个元素的 value 是集合对象, 则可以采用嵌套的<logic:iterate>标签遍历集合中的所有对象, 例如:

<%

HashMap h = new HashMap();

String vegetables[] = {"pepper","cucumber"};

String fruits[] = {"apple","orange","banana","cherry","watermelon"};

String flowers[] = {"chrysanthemum","rose"};

String trees[] = {"willow"};

h.put("Vegetables", vegetables);

h.put("Fruits",fruits);

h.put("Flowers",flowers);

h.put("Trees",trees);

request.setAttribute("catalog",h);

%>

<logic:iterate id="element" // 与<bean:write> 中的name 属性对应, 输出内容

indexId="ind" // 与<bean:write> 中的name 属性对应, 输出序号

name="catelog"> // 指定输出元素的名称

<bean:write name="ind"/>. // 输出序号

<bean:write name="element" // 与<logic:iterate>中id 属性对应

property="key"/> // 集合中的键名

<logic:iterate

id="elementValue" // 与<bean:write> 中的name 属性对应

name="element" // 指定输出元素的名称

property="value" // 集合中的键值

length="3" // 取3 个元素

offset="1"> // 从第 2 个位置取

-------<bean:write name="elementValue"/>

</logic:iterate>

</logic:iterate>

以上代码先定义一个名为"catelog" 的HashMap , 存放在request 范围内, 它的每个元素的value 为字符串数组.

接下来外层的<logic:iterate>标签遍历HashMap 中的所有元素, 内层的<logic:iterate>标签访问每个元素的value 属性, 遍历value 属性引用的字符串数组中的所有元素.

3. 设置被遍历的变量

可以通过以下方式来设置需要遍历的变量

(1) 设置name 属性, name 属性指定需要遍历的集合或Map, 例如:

<logic:iterate id="element" name="Animals">

<bean:write name="element"/>

</logic:iterate>

(2) 设置name 属性和property 属性, name 属性指定一个JavaBean, property 属性指定JavaBean 的一个属性, 这个属性为需要遍历的集合或Map, 例如:

<logic:iterate id="element" indexId="ind" name="catelog">

<bean:write name="ind"/>

<bean:write name="element" property="key"/>

<logic:iterate id="elementValue" name="element" property="value" length="3" offset="1">

--------<bean:write name="elementValue"/>

</logic:iterate>

</logic:iterate>

(3) 设置collection 属性, collection 属性指定一个运行时表达式, 表达式的运算结果为需要遍历的集合或Map, 例如:

<logic:iterate id="header" collection"<%=request.getHeaderNames()%>">

<bean:write name="header"/>

</logic:iterate>

4. 读取JavaBean 中的数据

(1) 在Jsp 页面中加入JavaBean 如:

<jsp:useBean id="articleClasses" class="com.GetArticleClasses"/>

上面这个JavaBean 要求必须存在一个集合数组对象,如Vector,Collection,ArrayList 等;在这个JavaBean 的构造函数中,取得数据

库中的数据,并将其存入数组对象中。

(2) 使用<logic:iterate> 标签,取出JavaBean 中存放的数组对象中的数据

<logic:iterate

id="aClasses" // id : 给检索出的元素所命的名.

name="articleClasses" // name : JavaBean 在页面中所设置的引用ID.

property="coll">   // coll : JavaBean 中的集合数组属性名称.

<tr>

<td onMouseOver="this.bgColor=''#FFFFFF''" onMouseOut="this.bgColor=''''">&nbsp;&nbsp;&nbsp;&nbsp;

<html:link page="/articleListAction.do"

paramId="classId"

paramName="aClasses"

paramProperty="classId">

<bean:write name="aClasses" // 与<logic:iterate> 标签中的id 属性相对应

property="className" /> // 取出JavaBean中, 存放在集合对象中的,对象的className 属性值

</html:link>

</td>

</tr>

</logic:iterate>

(3) 在JavaBean 中的集合对象中存放实体对象的语句如下:

显示代码

打印

public class GetArticleClasses

{

// 数据集合

private Collection coll;

// 返回数据集合

public Collection getColl()

{

return coll;

}

public GetArticleClasses()

{

coll = new ArrayList();

try{

// 数据库连接

Connection connection = DBConnection.getConnection();

if(connection != null)

{

Statement statement = connection.createStatement();

ResultSet resultset;

ArticleClass articleclass;

resultset = statement.executeQuery("SELECT * FROM table ORDER BY id");

while( resultset.next())

{

articleclass = new ArticleClass();

articleclass.setId(resultset.getInt("id"));

articleclass.setClassId(resultset.getString("class"));

articleclass.setClassName(resultset.getString("name"));

coll.add(articleclass))

}

resultset.close();

connection.close();

} else {

coll = null;

}

} catch(Exception exception) {

coll = null;

}

}

}

你可能感兴趣的:(struts2 页面遍历显示集合)