一、简介

   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. hadoop的lzo支持

    目录 1.下载相关文件: 2.Configure LZO to build a shared library (required) and use a package-specific prefix ...

  2. JAVA 批量下载服务器文件到本地指定文件夹并重命名

    /** * @功能 下载文件到指定文件夹并重命名 * @param url 请求的路径 * @param filePath 文件将要保存的目录 * @param filename 保存到本地的文件名 ...

  3. ffmpeg:为视频添加静态水印

    在ffmpeg中,添加水印需要用overlay滤镜,这是一个复杂滤镜,因为它需要两个输入,默认第一个输入是主画面,第二输入为水印,先执行一个简单的看看. 下面有两个文件,一个是可爱的大雄兔,一个是可爱 ...

  4. 在 2021 年你需要掌握的 7 种关于 JavaScript 的数组方法

    在新的一年我们学习这些有用的方法 JavaScript 为我们提供了许多处理数组的不同方法.我们将在几分钟内为您介绍 7 个基本且常用的数据方法,以提高您的 JS 开发技能. 1. Array.map ...

  5. Java基础语法:类型转换

    由于Java是强类型语言,所以有时候在进行运算时,需要用到类型转换. 整型.常量.字符类型数据可以混合运算. 运算中,不同类型的数据先转化为同一类型,然后再进行运算. 类型转换等级有低级到高级的划分, ...

  6. ADT基础(一)—— List,Stack,and Queue

    ADT基础(一)-- List,Stack,and Queue 1 List 表示 数组:易于search,难于insert和remove 链表:难于search,易于insert和remove // ...

  7. Centos7修改Docker默认存储位置

    一.前言 Centos7安装docker之后,默认的镜像及容器存储路径为/var/lib/docker,可以使用命令docker info查看. 但是该路径默认使用的是系统盘的存储,如果挂载了数据盘, ...

  8. Python列表元组和字典解析式

    目录 列表解析式List comprehensive 集合解析式Set comprehensive 字典解析式Dict comprehensive 总结 以下内容基于Python 3x 列表解析式Li ...

  9. 浮动引发的高度塌陷问题及其解决方法(BFC相关概念及性质)

    浮动引发的高度塌陷问题 高度塌陷问题的产生 BFC(Block Formatting Context)的引入 元素开启BFC后的特点 开启BFC的元素不会被其他浮动元素所覆盖 开启BFC的元素不会发生 ...

  10. 后端程序员之路 40、Pthreads

    POSIX线程(POSIX threads),简称Pthreads,是线程的POSIX标准.线程这个东西在操作系统原理里讲得比较清楚了,再加上对windows那一套进程线程的东西比较清楚,所以这里还是 ...