(十六)Struts2的标签库
一、简介
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的标签库的更多相关文章
- Struts2的标签库(五)——表单标签
Struts2的标签库(五) --表单标签 几个特殊的表单标签的使用: 1.checkboxlist标签 该标签用于创建多个复选框,用于同时生成多个<input type="check ...
- Struts2的标签库(四)——数据标签
Struts2的标签库(四) --数据标签 1.action标签 该标签用于在jsp页面直接调用一个Action,通过指定executeResult参数,还可以将Action的处理结果包含到此页面中来 ...
- Struts2的标签库(三)——控制标签
Struts2的标签库(三) --控制标签 1.if/elseif/else标签 用于分支控制,取代JSP中的if语句,根据一个boolean(test属性的值)值判断是否进行下一步运算或者输出等. ...
- Struts2的标签库(二)——OGNL表达式
Struts2的标签库(二) --OGNL表达式 1.Struts2中的OGNL表达式增加了ValueStack的支持. 注:ValueStack--实际上是一个容器对象,该对象在启动Struts2框 ...
- Struts2的标签库(一)——使用Struts2的标签库
Struts2的标签库(一) --使用Struts2的标签库 1.Struts2的标签库其实就是一个自定义的标签库,所以它也有它的标签处理类和标签库定义文件: 2.和所有自定义标签一样,我们可以找到S ...
- JavaWeb框架_Struts2_(五)----->Struts2的标签库
1. Struts2的标签库 1.1 Struts2标签库概述 Struts2的标签库可以分为以下3类:用户界面标签.非用户界面标签.AJAX标签; 2.1.1 Struts2标签库的分类和使用 1 ...
- Struts2之Struts2的标签库
前言: Struts2提供了大量的标签 ,用来帮助开发表现层页面,这些表现一方面解决了美观性的需求,因为它们具有html标签一样的外观,另一方面它们解决了功能性的需求, 因为它们具有jsp脚本一样的逻 ...
- (转)Struts2的标签库
http://blog.csdn.net/yerenyuan_pku/article/details/68638679 Struts2的标签库 对于一个MVC框架而言,重点是实现两部分:业务逻辑控制器 ...
- 二十 Struts2的标签库,数据回显(基于值栈)
通用标签库 判断标签:<s:if>.<s:elseif>.<s:else> 循环标签:<s:iterator> 其他常用标签: <s:proper ...
随机推荐
- 利用Metasploit 打入ThinkPHP内网...
出品|MS08067实验室(www.ms08067.com) 本文作者:dch(Ms08067实验室 SRSP TEAM小组成员) 一.利用Metasploit进行攻击的流程图 Metasploi ...
- kvm-PLE代码分析
Linux源码版本: 5.3.0 相关数据结构 #define KVM_DEFAULT_PLE_GAP 128 // ple_gap #define KVM_VMX_DEFAULT_PLE_WINDO ...
- Portainer中文汉化
一.概述 Portainer是Docker的图形化管理工具,提供状态显示面板.应用模板快速部署.容器镜像网络数据卷的基本操作(包括上传下载镜像,创建容器等操作).事件日志显示.容器控制台操作.Swar ...
- mysql 单表下的字段操作
如下只介绍单表的添加.更新.删除.查询表结构操作,查询数据操作范围太大用单独的篇幅来讲解: 查看表结构 desc test_tb; Insert 插入数据 插入 = 添加 为表中指定的字段插入数据 C ...
- CodeBlocks的安装配置以及使用教程
CodeBlocks的安装配置以及使用教程 教程写的很啰嗦,本来几句话就能搞定的,但为了照顾到那部分真正的小白还请大家见谅! 一.下载 前往CodeBlocks官网下载带编译器的版本,目前的最新版本为 ...
- Java 常见对象 03
常见对象·StringBuffer类 StringBuffer类概述 * A:StringBuffer类概述 * 通过 JDk 提供的API,查看StringBuffer类的说明 * 线程安全的可变字 ...
- Java 开发工具
开发工具·Eclipse 常见开发工具介绍 * A:操作系统自带的记事本软件 * B:高级记事本软件 * C:集成开发环境 IDE * (Integrated Development Envi ...
- Java 常见对象 05
常见对象·正则表达式 和 其他类 正则表达式的概述和简单使用 * A:正则表达式 * 是指一个用来描述或者匹配一系列符合某个语法规则的字符串的单个字符串.其实就是一种规则,有自己的特殊应用 * 作用: ...
- Java 集合框架 01
集合框架· ArrayList 和 Vector 对象数组的概述和使用 * A:案例演示 * 需求:我有5个学生,请把这5个学生的信息存储到数组中,并遍历数组,获取到每个学生的信息 Student[] ...
- php伪协议分析与CTF例题讲解
本文大量转载于:https://blog.csdn.net/qq_41289254/article/details/81388343 (感谢博主) 一,php:// 访问输入 ...