Struts笔记二:栈值的内存区域及标签和拦截器
值栈和ognl表达式
1.只要是一个MVC框架,必须解决数据的存和取的问题
2.struts2利用值栈来存数据,所以值栈是一个存储数据的内存结构
1、 ValueStack是一个接口,在struts2中使用OGNL表达式实际上是使用实现了ValueStack接口的类 OgnlValueStack,这个类是OgnlValueStack的基础。
2、 ValueStack贯穿整个action的生命周期。每一个action实例都拥有一个ValueStack对象。其中保 存了当前action对象和其他相关对象。
3、 Struts2把ValueStack对象保存中名为struts.valueStack的request域中。
3.把数据存放在值栈中,在页面上利用ognl表达式显示出来
4.ognl框架对象导航语言
5.ognl类图:
值栈的生命周期
1.一次请求;
值栈的内存结构
1.获取值栈路径:
2.说明:
1、 值是一样的,说明只有一个对象
2、 因为有一种是从request域中获取的,所以是一次请求
3内存结构:
1.大致图:
2.详细图:
说明:
_root:(CompoundRoot) _values:(HashMap)这里存放request、response、session、application等servlet容器
2._root图的放大:
说明:和ValueStack中的root是一致的
值栈的内存总图:
说明:从上图中可以看出valueStack总共分为两个部分: 对象栈:root Map栈:_values
1.1.1 OgnlContext组织结构
1.1.1.1 _values
从上述可以看出,OgnlContext实际上有一部分功能是Map。所以可以看出_values就是一个Map属性。而运行一下下面的代码就可以看到:
|
在_values的map中:
key |
value |
application |
ApplicationMap |
request |
RequestMap |
action |
自己写的action |
com.opensymphony.xwork2.ActionContext.session |
SessionMap |
而request中的值为:
|
可以看出在程序中存放在request作用域的值被放入到了_values的request域中。
而com.opensymphony.xwork2.ActionContext.session的值为:
|
从上图中可以看出在程序中被加入到session的值在_values中也体现出来。
1.1.1.2 _root
从图中可以看出_root实际上CompoundRoot类,从类的组织结构图中可以看出,这个类实际上是继承了ArrayList类,也就是说这个类具有集合的功能。而且在默认情况下,集合类的第一个为ValueStackAction,也就是我们自己写的action。
存放数据到值栈
1.1对象栈的存放:
方法1:
Push方法:
方法二:
add方法:
1.2.对象栈的提取(栈顶):
从上图可以看出,peek方法为获取对象栈的栈顶元素;
这行代码也可以获取对象栈的栈顶元素;
1.3.对象栈元素的弹出:
1.4.操作对象栈中的对象:
说明:可以利用valueStack的setParameter方法改变对象栈中的属性值;
关于对象栈:
从图中可以看出来,对象栈的属性来自于对象栈中的每一个对象的属性的get方法;
把一个对象放进对象栈中:
在<s:dubug></s:dubug>中:
如果在对象栈中存在两个相同的属性:案例:两个name
上述的两个类中都同时有name属性,而且当前请求的action在对象栈中
利用该方法就把person对象放入到栈顶了
可以利用上述的方法改变对象栈中的name属性,但是从上往下找,只要找到一个,改变了值就完事了。
2.Map栈的存放:
改方法将一个字符串放到map栈中的request域中;
通过该方法可以把一个字符串放入到map栈中的application域中
通过该方法可以把一个字符串放入到map栈中
Threadlocal
1.本地线程类;
2.可以存放一个对象;
3.Threadlocal对象只能当前线程访问,不能被其他线程访问;
4.传递参数;
案例:
说明:通过参数的传递,一个字符串很容易的从客户端传递到tl1中的tl1方法,再传递到tl2中的tl2方法
2.
说明:
在TL1Super中用到一个字符串
在TL2Super中用到同样的字符串,但是这两个类是完全松耦合,这个时候要用
Threadlocal传递数据,因为不管是否是送耦合的,但是可以肯定在同一个线程中。所以可以得到同一个线程threadlocal对象中的数据
显示值栈中的数据
6.1:Ognl标签:
1.导入标签库:
2.标签库位置:
3.action类:
4.作用:可以通过网页的形式把valueStack中值提取出来;
6.1.2:Property标签:输出标签
属性分析:value: 指定要输出的内容;如果在对象栈中直接指定属性也可以直接调用方法(该对象的方法);如果在Map栈中,用 # 指定,如果value属性不写,则默认输出栈顶的元素;
一:访问对象栈中的元素:
页面上:
把一个对象放入到对象栈中,可以利用s:prototype标签的value属性直接访问
该对象的属性。如果对象栈中出现两个相同的属性,则prototype标签的value属性会
从栈顶往下查找,直到找到为止。赋值的为第一个。
把一个对象放入到map中,再把map放入到对象栈中,在页面上可以利用
二:利用该标签访问Map栈中的元素:
注意:加 # 号访问
Map栈元素的访问:
6.1.3:Iterator标签:迭代器标签
1.用途:主要用于迭代,可以迭代List,Set,Map,Array
2.案例:
1.把集合放到对象栈中:
开始迭代:
2.把List放到map中;
开始迭代:
3.把List放到request域中:
把Map放入到Map栈中:
开始迭代:
5、把List<Map<String,Person>>放入到map栈中
标签属性:
Value:
可选属性,指定被迭代的集合。如果没有设置该属性,则使用对象栈顶的集合。
Var:
可选属性,引用变量的名称
Status:
可选属性,该属性指定迭代时的IteratorStatus实例。该实例包含如下的方法:
int getCount() 返回当前迭代的元素个数 int getIndex() 返回当前迭代元素的索引 boolean isEven() 返回当前迭代元素的索引是否是偶数 boolean isOdd() 返回当前迭代元素的索引是否是奇数 boolean isFirst() 返回当前迭代元素是否为第一个元素 boolean isLast() 返回当前迭代元素是否为最后一个元素
案例:
更多参考api
总结:
1、 如果要迭代一个集合,当前迭代的元素在栈顶
2、 如果要迭代一个map,则当前迭代的元素是entry
3、 Iterator标签中有一个属性status
6.1.4:UI标签:
1、 struts2提供了一套标签机制,由struts2框架把struts2的标签解析成html标签。
2、 在struts2的配置文件中,增加
在struts2的配置文件中加入如下的内容:
由struts2容器反应过来的HTML代码和struts2标签能保持一致;
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head> <body>
<s:form action="">
<table>
<tr>
<td>用户名</td>
<!--
name为翻译成html的name
cssClass为html的class
-->
<td><s:textfield name="username" cssClass=""></s:textfield></td>
</tr>
<tr>
<td>密码</td>
<td><s:password name="password"/></td>
</tr>
<tr>
<!--
select标签
list 是下拉列表框的数据源
value是默认被选中的值
-->
<td>选择省</td>
<td><s:select list="{'山西省','河南省','四川省'}" value="{'山西省'}"></s:select></td>
<td><s:select list="#{1:'山西省',2:'河南省',3:'四川省'}" value="#{2:'河南省'}"></s:select></td>
<td><s:select list="#provinces" listKey="pid" listValue="name"/></td>
<!--
listKey 为option元素的value属性的值
listValue option元素的文本内容
name
该属性的值用来获取选中的元素
用于回显
--> </tr>
<tr>
<td>选择爱好</td>
<td><s:checkboxlist list="{'足球','篮球','羽毛球'}" value="{'足球'}" name="pid"/></td>
<td><s:checkboxlist list="#{1:'足球',2:'篮球',3:'羽毛球'}" value="#{1:'足球'}" name="pid"/></td>
<!--
list代表数据源
listKey为value值
listValue为显示的值
-->
<td><s:checkboxlist list="#hobbies" listKey="hid" listValue="name" name="hid"/></td>
</tr>
<tr>
<td></td>
<td><s:submit/></td>
</tr>
</table>
</s:form>
</body>
</html>
UI.jsp
6.1.4.2、Select标签:
6.1.4.2、Checkbox标签:
1.1 Form标签
1.1.1 说明
1、 id属性为s:form的唯一标识。可以用document.getElementById()获取。
2、 name属性为s:form的名字,可以用document.getElementsById()获取。
3、 在默认情况下,s:form将显示表格的形式。
1.2 Textfield标签
1.2.1 说明
实际上相当于在表格中多了一行,在这行中多了两列。其变化从上述图中可以很明显的看出。
1.3 Password标签
1.3.1 说明
如果不加showPassword属性,则密码不会显示,把showPassword属性的值设置为true,就能显示密码。
1.4 Hidden标签
1.4.1 说明
Hidden标签并没有加tr和td
1.5 Submit标签
1.5.1 情况一
1.5.2 说明一
这种情况为submit的type属性为submit类型。
1.5.3 情况二:
1.5.4 说明二
这种情况submit的type属性为button.
1.5.5 情况三
1.5.6 说明三
该type类型为image。
1.5.7 综合
以上三种情况说明,当type为submit、button、image都能完成提交。
1.6 Reset标签
1.7 Textarea标签
1.8 Checkbox标签
1.9 Checkboxlist标签
1.9.1 集合为list
1.9.2 集合为map
上述的checkboxlist标签也可以表示为:
listKey相当于<input type=”checkbox”>中的value,listValue相当于label的显示值。
回显:
一. 概念:
在数据提交出现错误的时候, 已填写的信息仍在文本框中, 比如用户登录, 当用户输入错误的密码之后, 用户名仍在文本框, 只是密码框清空
二. 意义:
对于一些要填写很多信息的表单, 如果因为一些错误导致已经填写的整个表单信息重新填写, 对于用户非常地不友好
三. 回显方法:
1. 默认情况:根据属性进行回显
注意:如果把要回显的数据放入到map栈中、则必须根据value进行回显:Value="%{ognl表达式}"
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head> <body>
<s:form action="">
<table>
<tr>
<td>用户名</td>
<!--
s:select s:checkboxlist
这些标签中的list属性的值可以直接跟ognl表达式
一般情况下,表单中的元素的value属性都不能直接跟ognl表达式
可以使用%{ognl表达式}
如果要回显的内容在map栈中,不能根据name属性进行回显,必须用value属性进行回显
<td><s:textfield name="username" value="%{#user.username}"></s:textfield></td>
如果把要回显的对象放入到对象栈中,则页面上可以根据name进行回显
<s:textfield name="username"></s:textfield>
一般情况下,如果要回显一个对象,则把该对象放入到对象栈中
-->
<td><s:textfield name="username"></s:textfield></td>
</tr>
<tr>
<td>爱好</td>
<!--
用name进行回显
-->
<td><s:checkboxlist list="#hobbies" listKey="hid" listValue="name" name="hids"/></td>
</tr>
</table>
</s:form>
</body>
</html>
backview.jsp
1.回显Map栈中数据:
一般情况下,应该把回显的数据放入到对象栈中,因为页面上可以直接根据name进行回显
2. 回显对象栈中数据:
3.回显checkbox:
上述图表示要回显的id值
根据name属性进行回显
代码贴上:
package com.itheima09.struts.action; import java.util.ArrayList;
import java.util.List; import com.itheima09.struts.bean.Hobby;
import com.itheima09.struts.bean.Province;
import com.itheima09.struts.bean.User;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport; public class UIAction extends ActionSupport{
private Long[] hids; public Long[] getHids() {
return hids;
} public void setHids(Long[] hids) {
this.hids = hids;
} private Long pid; public Long getPid() {
return pid;
} public void setPid(Long pid) {
this.pid = pid;
} public String testSelect(){
List<Province> provinces = new ArrayList<Province>();
Province province1 = new Province();
province1.setPid(1L);
province1.setName("山西省");
Province province2 = new Province();
province2.setPid(2L);
province2.setName("河南省"); Province province3 = new Province();
province3.setPid(3L);
province3.setName("四川省"); provinces.add(province1);
provinces.add(province2);
provinces.add(province3); this.pid = 3L; ActionContext.getContext().put("provinces", provinces);
return "ui";
} public String testCheckbox(){
List<Hobby> hobbies = new ArrayList<Hobby>();
Hobby hobby1 = new Hobby();
hobby1.setHid(1L);
hobby1.setName("足球");
Hobby hobby2 = new Hobby();
hobby2.setHid(2L);
hobby2.setName("蓝球"); Hobby hobby3 = new Hobby();
hobby3.setHid(3L);
hobby3.setName("荷兰球"); hobbies.add(hobby1);
hobbies.add(hobby2);
hobbies.add(hobby3); ActionContext.getContext().put("hobbies", hobbies); return "ui";
} /**
* 回显用户名
*/
public String testBackViewUsername(){
User user = new User();
user.setUsername("王二麻子");
user.setPassword("123456");
//ActionContext.getContext().put("user", user);
//ActionContext.getContext().put("username", "aaa");
ActionContext.getContext().getValueStack().push(user);
return "backview";
} /**
* 回显爱好中的值
*/
public String testBackViewHobby(){
/**
* 在页面上把checkbox的内容显示出来
*/
List<Hobby> hobbies = new ArrayList<Hobby>();
Hobby hobby1 = new Hobby();
hobby1.setHid(1L);
hobby1.setName("足球");
Hobby hobby2 = new Hobby();
hobby2.setHid(2L);
hobby2.setName("蓝球");
Hobby hobby3 = new Hobby();
hobby3.setHid(3L);
hobby3.setName("荷兰球");
hobbies.add(hobby1);
hobbies.add(hobby2);
hobbies.add(hobby3);
ActionContext.getContext().put("hobbies", hobbies); /**
* 用于回显
*/
this.hids = new Long[2];
this.hids[0] = 1L;
this.hids[1] = 2L;
return "backview";
}
}
UIaction
拦截器
需求:如果要访问某一个action类中的某一个方法的内容,如果是admin用户则访问,如果不是admin用户则不能访问。
实现:
7.1:编写一个拦截器(步骤):
7.1.1:编写interceptor:
7.1.2:写一个pvilegeSuperAction:
7.1.3:在配置文件中进行配置:
解析:
说明:
通过该图可以看出:当提交一个url请求时,先执行所有的拦截器(按照声明的从上到下的顺序),再执行action。
声明一个拦截器
声明一个拦截器栈
既可以引用一个拦截器
也可以引用一个拦截器栈
真正的做法:
如果p包继承了privilege包就把所有的新的拦截器栈继承过来了,如果没有继承,则执行默认的拦截器栈
缺点
把权限判断的代码和业务逻辑的代码混合在一起了
1.1 实现方案一
|
说明:
1、 这样做,程序的结构不是很好。原因是权限的判断和业务逻辑的方法紧密耦合在了一起。如果权限的判断很复杂或者是业务逻辑很复杂会造成后期维护的非常困难。所以结构不是很好
2、 这种形式只能控制一个action中的一个方法。如果很多action中的很多方法都需要这种控制。会导致大量的重复代码的编写。
1.2 实现方案二
动态代理可以实现。请参见cn.itcast.struts.jdkproxy包下的类。
1.3 实现方案三
在struts2中,用拦截器(interceptor)完美的实现了这一需求。在struts2中,
内置了很多拦截器,在struts-default.xml文件中可以看出。用户还可以自定义 自己的拦截器。自定义拦截器需要以下几点:
1、 在配置文件中:
包括两个部分:声明拦截器栈和使用拦截器栈
|
2、 在拦截器类中
一个类如果是拦截器,必须实现Interceptor接口。
|
案例2.在执行action的方法之前,
1、 开启日志
2、 权限的检查
1步骤:声明两个拦截器:
2.在执行的拦截器栈中,按照执行的先后顺序引入拦截器
注意:1.等我解决了在写QAQ
7.2,拦截器的应用:
7.2.1.属性驱动:
注意事项:
1、 必须使用struts2默认的拦截器栈中的ParametersInterceptor
2、 Action中的属性和表单中的name属性的值保持一致
3、 利用valueStack.setValue方法可以赋值了
模型驱动:
背景:
假设你正在完成一个网站的注册功能。在后台需要得到20多个属性,才能完成注册。如果用action中的属性获取值,就是这样的情况:
1、 在action中会写20个属性
2、 这20个属性添加set和get方法。
说明:这样会导致action中的代码结构不是很好。模型驱动很好的解决了这个问题。
从上图可以看出,ModelDriverInterceptor有两个作用:
1、 当前请求的action必须实现ModelDriver接口
2、 把model对象放入到了栈顶
1.验证:
1.防止表单的重复提交:
2.文件上传:
3.类型转换:
Struts笔记二:栈值的内存区域及标签和拦截器的更多相关文章
- 【Java】「深入理解Java虚拟机」学习笔记(2)- JVM内存区域
一.运行时数据区 JVM在执行Java程序的时候,将其运行时数据区划分为若干不同区域.它们的用途和创建及销毁的时间不同. 1.程序计数器(Program Counter Register) 是一块很小 ...
- 深入理解Java虚拟机学习笔记(一)-----Java内存区域
一 概述 对于 Java 程序员来说,在虚拟机自动内存管理机制下,不再需要像C/C++程序开发程序员这样为内一个 new 操作去写对应的 delete/free 操作,不容易出现内存泄漏和内存溢出问题 ...
- 走进JVM【二】理解JVM内存区域
引言 对于C++程序员,内存分配与回收的处理一直是令人头疼的问题.Java由于自身的自动内存管理机制,使得管理内存变得非常轻松,不容易出现内存泄漏,溢出的问题. 不容易不代表不会出现问题,一旦内存泄漏 ...
- 《深入理解Java虚拟机》笔记--第二章、Java内存区域与内存溢出异常
Java程序员把内存的控制权交给了Java虚拟机.在Java虚拟机内存管理机制的帮助下,程序员不再需要为每一个new操作写对应的delete/free代码,而且不容易出现内存泄露和溢出. 虚拟机在执行 ...
- 【原】Learning Spark (Python版) 学习笔记(二)----键值对、数据读取与保存、共享特性
本来应该上周更新的,结果碰上五一,懒癌发作,就推迟了 = =.以后还是要按时完成任务.废话不多说,第四章-第六章主要讲了三个内容:键值对.数据读取与保存与Spark的两个共享特性(累加器和广播变量). ...
- jvm虚拟机笔记<二> 垃圾回收与内存分配
确定对象已废弃需要两步: 利用可达性分析算法(与GC roots有关联——虚拟机栈中的对象,方法区静态对象,方法区常量对象,本地方法引用的对象)判断是否需要回收. 是否覆盖过finalize方法并执行 ...
- 深入理解Java虚拟机读书笔记(一)- java内存区域和垃圾收集
jvm内存模型如下图 垃圾回收: 方法区: 这部分的垃圾回收性价比低,一般不要求回收,暂认为是永久代 heap:新生代和永久代之分.永久代主要回收废弃常量和无用的类. 垃圾回收算法: 1. 标记-清除 ...
- 二、spring集成ibatis进行数据源事务管理拦截器环境配置
1.dataSource-applicationContext.xml文件配置理解:(spring1.2.8+ibatis1.5.3)1.1)配置数据源 DriverManagerDataSource ...
- JVM 学习笔记二 :JVM内存区域
一.内存分配概述
随机推荐
- HahMap相关问题
概述 文章对HashMap的部分细节进行介绍,JDK1.7之前有可能出现环形表的问题,而1.7之后进行了改进,文章对环形表现象的出现进行了解析,然后对HashMap注意的几个问题进行了解答. Hash ...
- python报错使用yum命令报错File "/usr/bin/yum", line 30 except KeyboardInterrupt, e: SyntaxError: invalid syntax问题
参考链接:https://blog.csdn.net/ltz150/article/details/77870735 1.背景: CentOS 7升级Python到3.6.2后,需要在/usr/bin ...
- EntityFramework 插入自增ID主从表数据
原因: 数据库中的两个表是主从表关系,但是没有建外键,而表的id用的是数据库的自增整数,导致在使用EF导入主从表数据时,需要先保存主表数据,取到 主表的自增id后才能插入从表数据,这样循环之下,数据插 ...
- 攻防世界 你知道php备份文件吗?
题目地址:https://adworld.xctf.org.cn/task/answer?type=web&number=3&grade=0&id=5064 php的备份有两种 ...
- window下进程退出后自动重启
设计思想:编写批处理脚本监控进程的运行状态,如果发现进程停止,则自动重启该进程.批处理脚本(jk.bat)和进程脚本(hello.bat)如下: 1.jk.bat @echo off rem 定义需监 ...
- 4500-X启动到“511K bytes of non-volatile configuration memory”,无法继续?
在设备做了某些配置后,尤其是升级,重启设备后,发现设备在如下界面卡住,无法进一步进入CLI命令行. Platform Manager: starting in standalone mode (act ...
- JZOJ5915 [2018NOIP模拟] 明日之星(广义后缀自动机,线段树)
题目描述 给定一棵树,每个节点有一个权值 \(a_i\) 和一个字符串 \(s_i\). q组询问,每次询问一个字符串 S 和两个节点x,y: 求x到y路径上每个节点的字符串在 S 中出现的次数乘上各 ...
- Redis搭建一主一从及哨兵模式(二)
废话不多说,直接进入正题. 一.主从搭建 进入redis的根目录,拷贝一份redis.conf,最初的一份留作模版: ①cp redis.conf redis.conf.template ②vim ...
- 《【架构设计之道】这一波优雅的操作,会把你的中间件系统架构带到另一个Level》阅读笔记
(1) Master-Slave架构 这个中间件系统的本质是希望能够用分布式的方式来处理一些数据,但是具体的作用涉及到核心技术,这里不能直接说明. 但是他的核心思想,就是把数据分发到很多台机器上 ...
- C语言:将s所指字符串中下标为偶数同时ASCII值为奇数的字符删去,-将a所指字符串中的字符和b所指字符串中的字符的顺序交叉,-将形参s所指字符串中的所有数字字符顺序前移,
//函数fun功能:将s所指字符串中下标为偶数同时ASCII值为奇数的字符删去,s所指串中剩余的字符形成的新串放在t所指的数组中. #include <stdio.h> #include ...