一、简介

   Struts2的标签库使用OGNL为基础,大大简化了数据的输出,也提供了大量标签来生成页面效果,功能非常强大。

    在早期的web应用开发中,jsp页面主要使用jsp脚本来控制输出。jsp页面嵌套大量的java脚本。
导致页面的可读性较差,可维护性也很低,页面美工人员不懂java,java开发人员也不懂美工设计。
JSP规范1.1之后,增加了自定义标签库的规范。
通过使用自定义标签库,在简单的标签中封装复杂的功能,从而避免了jsp页面中出现大量java代码。
JSP规范制订了一个标准的标签库,JSTL。 Struts2的标签库的标签不依赖于任何表现层技术,也就是说,Struts2提供的标签,可以在各种表现层技术中使用,包括jsp页面。 Struts2的标签主要分为三类
-UI标签:主要用于生成HTML元素的标签
-非UI标签:主要用于数据访问,逻辑控制等
-Ajax标签:用于Ajax支持的标签

二、OGNL表达式

(1)概述

        Struts2利用内建的OGNL表达式语言支持,大大增加了Struts2的数据访问功能,Xwork在原有的OGNL的基础上,增加了对ValueStack的支持。

        我们每次发出请求时,都会产生请求数据,这些数据存放在哪里呢?
在每次动作执行前,核心控制器都会创建一个ActionContext对象,每次动作访问都会创建。 context map是OGNL上下文对象,是一个Map集合,Struts2中将ActionContext设置为OGNL上下文,但内部还是使用的OGNL context,包含了Stack Context和ValueStack对象, 里面包含着以下内容
Stack Context里包含 application,session,request,parameters,attr |--application 是一个Map,封装着application域的属性
|
|--session 是一个Map,封装着session域的属性
(ActionContext)context map---|
|--request 是一个Map,封装着request域的属性
|
|--parameters 是一个Map,封装着请求参数
|
|--attr (searches page, request, session, then application scopes) 是一个Map,封装着四个域的所有属性,依次按照PageContext,request,session,application的顺序进行搜索属性。
|
|--value stack(root) 是一个List
|
|--action (the current action):当前action的引用 当系统创建Action实例后,Action实例被保存到ValueStack中。 我们可以在页面上用 <s:debug></s:debug> 标签来查看 ValueStack和Stack Context里的数据。

 (2)OGNL中的集合操作

        创建List集合的语法{e1,e2,e3...}
创建Map集合的语法#{key1:value1,key2:value2,....}

 (3)OGNL访问静态成员

        (一)访问静态属性
@全类名@静态属性
例如我们Integer类中有一个MAX_VALUE
<s:property value="@java.lang.Integer@MAX_VALUE"/>
会在页面输出2147483647 (二)访问静态方法
@全类名@静态方法
Struts2默认禁用访问静态方法,我们可以在struts.xml中设置使用。
<constant name="struts.ognl.allowStaticMethodAccess" value="true"/> 然后在jsp页面就可以访问静态方法
<s:property value="@java.lang.Math@random()"/>

  (4)OGNL的表单标签

       -checkboxlist:复选框。
-select:下拉列表
等等很多,可以自己查阅使用。

  (5)OGNL的常用标签

         控制标签可以完成流程控制,如分支,循环等,也可完成对集合的合并、排序等。

         (一)if/elseif/else标签
用于分支控制,根据boolean表达式,决定是否计算,输出内容等。
三个标签可以组合使用,但只有<s:if ../>标签可以单独使用
语法:
<s:if test="表达式">
标签体
</s:if>
<s:elseif test="表达式">
标签体
</s:elseif>
....
可以有多个elseif
....
<s:else>
标签体
</s:else> (二)iterator标签
用于对集合进行迭代,这里的集合包括List,set和数组,也可对Map进行迭代输出。
属性
-value:可选属性,指定被迭代的集合。如果没有指定该属性,则迭代ValueStack栈顶的集合。
-var:可选属性,指当前迭代的集合元素,如果写了该属性,把var的值作为key,当前遍历的元素作为value,存到Stack Context中。如果不写该属性,就把当前遍历的元素压入栈顶。
-status:可选属性:是一个对象的名称,该对象包含一些迭代时的计数信息方法,该对象放在Stack Context中。
* int getCount();返回当前迭代了几个元素
* int getIndex();当前迭代元素的索引
* boolean isEven()/isOdd();当前元素的索引是否是偶数/奇数。
* boolean isFirst()/isLast();当前元素是否是第一个/最后一个元素
-begin/end:开始和结束的索引
-step:步长 (三)set标签
将var属性作为Key,为字符串,将Value属性作为Value,为OGNL表达式,存到StackContext中。
<s:set value="'test'" var="str"/> (四)append标签
用于将多个集合对象拼接起来,组成一个集合,通过这种拼接,就可以使用一个<s:iterator />标签完成对多个集合的迭代
var属性:指定新拼接生成的新集合名称 并且放入stack Context中
param属性:指定一个集合 <s:append var="newList">
<s:param value="{e1,e2.e3...}"/>
....
</s:append> (五)generator标签
用于将字符串按照指定分隔符分割成多个子串(一个list集合来存放)。临时生成的多个字串可以进行迭代。
count:可选属性。指定生成集合中元素的总数。
value:必填属性。指定被解析的字符串
separator:必填属性。指定字符串的分隔符
var:可选属性。如果指定该属性,则生成的集合以该名称放入Stack Context中。 <s:generator separator="," val="'e1,e2,e3'">
<s:iterator status="st">
<s:property/>
</s:iterator>
</s:generator> (六)action标签
允许在jsp页面调用action。如果指定了executeResult参数的属性值为true,该标签还会把action的处理结果包含在本页面中。 (七)url标签
用于生成一个url地址。
属性
*action:可选属性。指定url地址为哪个action,不写的话,使用Value为url地址
*value:可选属性。指定url地址为哪个action,不写的话,使用action为url地址
*method:可选属性。指定action的方法
<s:url value="save">
<s:param name="name" value="'zhangsan'"></s:param>
</s:url>

  (6)OGNL的数据存取

我们发送请求时,核心控制器会创建ActionContext,里面包含Stack Context和ValueStack。

  

三、StackContext中存取数据

(1)向StackContext中存放数据,ActionContext是一个Map

                    第一步:创建一个Action类
public class SaveDemo extends ActionSupport {
public String execute(){
//获取ActionContext
ActionContext context=ActionContext.getContext();
//存放数据
context.put("hello", "hello context");
return SUCCESS;
}
}

配置Action

                    <action name="save" class="com.cad.struts2.action.SaveDemo">
<result>/Demo.jsp</result>
</action>

查看ActionContext里的内容,使用<s:debug />标签 会发现有一行 hello hello context 说明已经存入。

(2)向StackContext中的Session,application,attr等里面存放数据

 我们前面说过ActionContext是一个Map,里面包含的request,session等也都是Map。

第一步:创建Action类

                    public class SaveDemo extends ActionSupport {
public String execute(){
//第一种获取ActionContext中的session,是一个Map集合
Map<String,Object> session=ActionContext.getContext().getSession();
session.put("hello", "hello session");
//第二种,获取ServletAPI,存放
HttpSession s=ServletActionContext.getRequest().getSession();
s.setAttribute("session", "session888");
return SUCCESS;
}
}

  

第二步:Stack Context中取数据

                <body>
<!--取ActionContext中的数据,通过#key读取-->
<s:property value="#hello"/>
<br>
<!--取Session中,通过#key.session map中的key-->
<s:property value="#session.hello"/>
</body>

四、ValueStack中存取数据

  struts2在请求到来时,会创建ValueStack,将当前的Action对象放入栈顶。 Struts2把ValueStack存放在request中,所以我们可以在request中获取ValueStack对象。 ValueStack是值栈,先进后出,后进先出。

 (1)存数据

                public class SaveDemo extends ActionSupport {
public String execute(){
/*//获取ValueStack对象
HttpServletRequest request=ServletActionContext.getRequest();
ValueStack vs1=(ValueStack) request.getAttribute("struts.valueStack");
System.out.println(vs1); //第二种获取ValueStack的方法
ActionContext context=ActionContext.getContext();
Map<String,Object> map=(Map<String, Object>) context.get("request");
ValueStack vs2=(ValueStack) map.get("struts.valueStack");
System.out.println(vs2);*/ //第三种方式获取ValueStack方法
ActionContext context=ActionContext.getContext();
ValueStack vs3=context.getValueStack();
//将对象压栈
vs3.push(new User("张三",18));
return SUCCESS;
}
}

  (2)取数据

                //只能取对象中的属性,ValueStack是list集合,里面是一个一个元素,我们只能取元素的属性,比如user对象的username,age等,不能取这个对象
//由于ValueStack是根对象,取ValueStack中的对象属性时,不使用#。
//从栈顶开始逐个对象查找指定的属性名称,只要找到就不再继续查找
<s:property value="username"/>

  (3)ValueStack案例

我们在我们的Action类中也设置一个username属性

  

                    public class SaveDemo extends ActionSupport {
private String username="李四";
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String execute(){ ActionContext context=ActionContext.getContext();
ValueStack vs3=context.getValueStack();
vs3.push(new User("张三",18)); return SUCCESS;
}
}

  

由于我们发送请求时,会将请求的Action实例先压入栈,然后再将我们的对象压栈
如图,栈里有两个username,我们怎么取动作类里的username呢? 可以使用索引来查找,从0开始,代表属性的索引 所以。
<s:property value="[0].username"/><br>
<s :property value="[1].username"/> 输出 :
张三
李四

  (4)ValueStack的其他方法

                -setValue(String expr,Object value):expr是OGNL表达式,value是数据。这个方法是存放数据,存到哪里看OGNL表达式
如果OGNL表达式使用#,则存放到ActionContext中 没有使用,就存放到ValueStack中 vs3.setValue("#username", "王五"); //将数据存到ActionContext中,username是key,王五是值 vs3.setValue("username", "赵六"); //将ValueStack中的第一个username替换成赵六。如果类中没有username的set方法。就不会替换和设置。 -void set(String key,Object o); key是Map的key,o是Map的value。
这个方法如果栈顶是一个Map元素,就把key作为map的key,把Object作为map的value。设置进去。 如果栈顶不是Map元素,则创建一个Map对象,把Key作为map的key,Object作为map的value,压入栈顶。 vs3.set("user1",new User("刘德华",54) ); 在页面中怎么取呢?这是一个Map对象,是key和value,并没有属性
<s:property value="user1.username"/> 当我们使用<s:property />元素不指定Value时,默认输出当前栈顶的元素。 -findValue(String expr):根据OGNL表达式查找
其实我们的<s:property />标签的原理就是这个
ValueStack vs=ActionContext.getContext().getValueStack();
Object obj=vs.findValue(OGNL表达式)

 

五、Struts2对EL表达式的改变

我们来看一个例子,我们先创建一个Action,action有一个属性username

        public class SaveDemo extends ActionSupport {
private String username="Action类中的值"; public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String execute(){
return SUCCESS;
}
}

  

                我们在动作类中有一个username属性,当我们请求action时,该Action对象被压入栈顶。该属性也存在Action对象中。           

                我们在页面输出这个username,用EL表达式和OGNL表达式
<body>
<s:debug></s:debug>
EL表达式:${username }<br>
OGNL表达式:<s:property value="username"/>
</body> EL表达式是按照指定的域的顺序查找,我们没有向域中存入数据,所以应该查找不出来,但结果却出乎意料 结果:
EL表达式:Action类中的值
OGNL表达式:Action类中的值 这是为什么呢?

  

        我们再来向request域中存值,来看看EL表达式是否还和以前一样按照顺序取值
public class SaveDemo extends ActionSupport {
private String username="Action类中的值"; public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String execute(){
HttpServletRequest request=ServletActionContext.getRequest();
request.setAttribute("username", "request域中的值"); return SUCCESS;
}
} 这时候输出结果
request域中的值
Action类中的值

  

        我们接着向Session中放入值

                    public class SaveDemo extends ActionSupport {
private String username="Action类中的值"; public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String execute(){
HttpServletRequest request=ServletActionContext.getRequest(); HttpSession session=request.getSession();
session.setAttribute("username", "session中的值");
return SUCCESS;
}
}
页面中的EL表达式应该显示Session中的值,结果却又出人意料
结果:
EL表达式:Action类中的值
OGNL表达式:Action类中的值 这就说明EL的取值顺序改变了。这是怎么回事呢?
            这是因为struts2对request进行了包装
通过StrutsRequestWrapper类对request进行包装 struts2通过EL表达式获取数据时,先从request中找,找到就返回该属性。
如果没找到,就从ValueStack中找,如果没找到,就去StackContext map中找,没找到再去session,application中找,这就是struts2对EL表达式的改变。

  

  

 

(十六)Struts2的标签库的更多相关文章

  1. Struts2的标签库(五)——表单标签

    Struts2的标签库(五) --表单标签 几个特殊的表单标签的使用: 1.checkboxlist标签 该标签用于创建多个复选框,用于同时生成多个<input type="check ...

  2. Struts2的标签库(四)——数据标签

    Struts2的标签库(四) --数据标签 1.action标签 该标签用于在jsp页面直接调用一个Action,通过指定executeResult参数,还可以将Action的处理结果包含到此页面中来 ...

  3. Struts2的标签库(三)——控制标签

    Struts2的标签库(三) --控制标签 1.if/elseif/else标签 用于分支控制,取代JSP中的if语句,根据一个boolean(test属性的值)值判断是否进行下一步运算或者输出等. ...

  4. Struts2的标签库(二)——OGNL表达式

    Struts2的标签库(二) --OGNL表达式 1.Struts2中的OGNL表达式增加了ValueStack的支持. 注:ValueStack--实际上是一个容器对象,该对象在启动Struts2框 ...

  5. Struts2的标签库(一)——使用Struts2的标签库

    Struts2的标签库(一) --使用Struts2的标签库 1.Struts2的标签库其实就是一个自定义的标签库,所以它也有它的标签处理类和标签库定义文件: 2.和所有自定义标签一样,我们可以找到S ...

  6. JavaWeb框架_Struts2_(五)----->Struts2的标签库

    1.  Struts2的标签库 1.1 Struts2标签库概述 Struts2的标签库可以分为以下3类:用户界面标签.非用户界面标签.AJAX标签; 2.1.1 Struts2标签库的分类和使用 1 ...

  7. Struts2之Struts2的标签库

    前言: Struts2提供了大量的标签 ,用来帮助开发表现层页面,这些表现一方面解决了美观性的需求,因为它们具有html标签一样的外观,另一方面它们解决了功能性的需求, 因为它们具有jsp脚本一样的逻 ...

  8. (转)Struts2的标签库

    http://blog.csdn.net/yerenyuan_pku/article/details/68638679 Struts2的标签库 对于一个MVC框架而言,重点是实现两部分:业务逻辑控制器 ...

  9. 二十 Struts2的标签库,数据回显(基于值栈)

    通用标签库 判断标签:<s:if>.<s:elseif>.<s:else> 循环标签:<s:iterator> 其他常用标签: <s:proper ...

随机推荐

  1. c++指针练习

    Pointers 在getchar处断点,断点后,调试->窗口->反汇编 查看数据 main #include <iostream> #include <Windows. ...

  2. 我眼中的价值币——NGK(下)

    跨链交互方案并不是区块链世界中的一个新课题.自比特币诞生揭开智能合约的序幕之后,跨链交互的需求便产生了.但是,经过十年的发展,市场中的跨链解决方案进展缓慢,究之原因有以下几个方面. 首先,区块链的去中 ...

  3. 「NGK每日快讯」12.3日NGK公链第30期官方快讯!

  4. 1022 Digital Library——PAT甲级真题

    1022 Digital Library A Digital Library contains millions of books, stored according to their titles, ...

  5. iOS图片预览、放大缩小

    思路 图片预览,优先考虑基础控件UIImageView.UIButton 图片预览中可能需设置不同的mode,优先考虑UIImageView typedef NS_ENUM(NSInteger, UI ...

  6. linux查看目录文件以及子目录文件大小的命令

    可以使用以下命令,不过如果文件比较多,因为是递归统计大小的的,所以结果出来的会比较慢,需要等待. du -h --max-depth=1 * 以下是命令的说明 du [-abcDhHklmsSx] [ ...

  7. Spring中的依赖查找和依赖注入

    作者:Grey 原文地址: 语雀 博客园 依赖查找 Spring IoC 依赖查找分为以下几种方式 根据 Bean 名称查找 实时查找 延迟查找 根据 Bean 类型查找 单个 Bean 对象 集合 ...

  8. mysql查询缓存简单使用

    MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品.MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBM ...

  9. (数据科学学习手札110)Python+Dash快速web应用开发——静态部件篇(下)

    本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的系列教程Python+Dash快速web ...

  10. Java 重入锁和读写锁

    本文部分摘自<Java 并发编程的艺术> 重入锁 重入锁 ReentrantLock,顾名思义,就是支持重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁.除此之外,该锁还支持获取锁时 ...