接着Struts2_3_day的讲

注:使用Struts2的< s:debug>< /s:debug>就可获取数据储存的分布图

StrutsPrepareAndExecuteFilter都会创建一个ActionContext和ValueStack对象, 所以Struts2的数据存储分为两类: ActionMap(contextMap)以及ValueStack; ActionMap中都是以map的形式存取数据, 而ValueStack是以Stack的方式存取数据(底层就是List)

ActionMap数据操作

  1. 利用ActionMap存储数据
    ActionMap是一个大的map, 而这个大map中又存有application, session, request, parameters, attr的小map, 所以在ActionMap中存放数据的时候既能存入大map中, 也能存入小map中, 在小map中还能存入map, 形成多层的存储, 如下代码操作:
1.直接在ActionMap中存入数据, 使用ActionMap的静态方法getContext获取ActionMap对象, 然后直接putActionMap context = ActionMap.getContext();context.put("contextMap", "contextMap");2.往ActionMap中的session对象中存入数据使用ActionMap中的session, session也是一个mapMap<String, Object> sessionAttribute = context.getSession();sessionAttribute.put("sessionMap1", "sessionMap1");使用原始HttpSession对象存储数据HttpSession session = ServletActionContext.getRequest().getSession();session.setAttribute("sessionMap2", "sessionMap2");3.往ActionMap的application中存入数据使用使用ActionMap中的ServletContext域Map<String, Object> applicationAttribute = context.getApplication();application.put("applicationMap1", "applicationMap1");使用原始ServletContext对象ServletContext application = ServletActionContext.getServletContext();application.setAttribute("applicationMap2", "applicationMap2");

注: 无论使用ServletActionContext中的存储方式, 还是使用ActionMap.getContext().getXXX()的方式, 他们所指向的存储区域都是一样的, 例如上面的applicationMap1和applicationMap2, 他们二者的数据都是存放在同一片储存区域的, 同理sessionMap1与sessionMap2也是一样的

  1. 获取ActionMap中数据
    可以直接使用Map的get, 或者使用域对象的getAttribute方法来获取ActionMap中数据, 但是大多数使用OGNL表达式在jsp中获取ActionMap数据, 例如:
// 使用OGNL表达式获取域对象数据, OGNL表达式必须写在Struts2的标签中
<%@ taglib uri="/struts-tags" prefix="s" %>
<s:property value="#session.sessionMap1">
//在使用OGNL表达式取用ActionMap的数据的时候, 使用"#" //借用上面代码的存储方式, 因为sessionMap1,以及sessionMap2是存入session中, 所以直接使用#session.sessionMap1
//数据的查找顺序是: 先去ActionMap中查找session区域, 找到之后在session区域中查找是否具有key为sessionMap1的数据//同理, 当查找applicationMap1也是直接使用:<s:property value="#application.applicationMap1">

ValueStack数据操作

  1. 利用ValueStack存储数据
    正如前面所说的, ValueStack就是一个Stack结构, 当我们向ValueStack中存入数据的时候就是进行入栈, 出栈的操作

下面先介绍获取ValueStack对象引用的3种常见方式:

1.使用<s:debug></s:debug>之后发现, 在request中存有ValueStack的引用, 所以可以使用get的方式获取:ActionContext context = ActionContext.getContext();Map<String, Object> request = (Map<String, Object>) context.get("request");ValueStack vs = (ValueStack)request.get("struts.valueStack");2.使用ServletActionContext获取request对象, 然后再通过getAttribute获取:ServletRequest request = ServletActionContext.getRequest();ValueStack vs = (ValueStack)request.getAttribute("struts.valueStack");3.直接使用ActionContext对象的getValueStack方法获取:ValueStack vs = ActionContext.getContext().getValueStack();注: 通过上面的3种方式获取的vs都是同一个对象

当我们获取到ValueStack对象之后就可以对ValueStack对象做push, peek/pop操作以此达到存储数据的目的, 例如:

ValueStack vs = ActionContext.getContext().getValueStack();
vs.push(new Student("A", 18)); //对一个Student对象做入栈操作

注: 默认动作类对象会自动存入ValueStack中, 因此可以通过OGNL表达式获取默认动作对象的属性方法(对该属性一定要写set/get方法)

  1. 获取ValueStack中数据
    当使用动作类进行ValueStack存储数据的时候, 一定要记住: 如果直接想通过OGNL表达式获取, 此时数据只具有request的作用域范围, 当使用页面重定向后, 就不能访问到刚才动作方法中存入ValueStack中的数据
 1.可以使用pop/peek直接获取ValueStack数据或者jsp中使用标签的方式获取ValueStack数据; 2.jsp中操作: 使用< s:property value="name" />这里的name是一个OGNL表达式, 用于获取Student中的name属性;3.与获取ActionContext数据不同的是, value后面的参数少了一个"#", **"#"是作为获取ValueStack与ActionMap中数据的一种区别**;4.在ValueStack中, 查找方式是: 在Stack中依次遍历每个对象, 查看当前对象的属性是否是value后面的参数值,如果是就代表找到, 就不再往后查找. 例如: 当动作类中也具有一个name属性, 但是现在栈顶是一个Student对象, 当找到Student对象中的name属性的时候就不再往后找, 即使动作类中也具有name;5.在OGNL表达式中可以多级访问: 比如ValueStack中存入的数据是一个Map对象map, Map对象中存有一个Student对象s1, 当我们想要获取此时Student对象的name属性的时候, 就可以写:< s:property value="s1.name" />
  1. ValueStack的set与setValue方法的区别
set方法:
ValueStack vs = ActionContext.getContext().getValueStack();
vs.push(new Student("A", 19));
vs.set("s1", new Student("B", 20));如上述代码, 当vs使用set操作的时候, 操作的元素是ValueStack中的元素.
如果栈顶是一个Map, 就直接将一个key为s1, value为Student对象存入Map中
如果栈顶不是一个Map, 则ValueStack新建Map<String, Object>对象, 然后将key为s1, value为Student对象存入Map中当连续多次vs.set()的时候, 所有的set的对象都是存入一个Map对象中, 例如:vs.set("s1", new Student("A", 20));vs.set("s2", new Student("B", 10));vs.set("s3", new Student("C", 24));当使用OGNL表达式访问栈中map中的元素, 采用: <s:property value="s1.name"/>, 而不是<s:property value="#s1.name">, 这里是在ValueStack中取元素, 而不是ActionMap
在获取元素的时候, 元素对象一定要写set/get方法
这里别理解为连续set是建立多个map, 只有在下面这种情况下, 才是建立多个Mapvs.set("s1", new Student("A", 20)); //新建一个mapvs.push(new Student("C", 24));vs.set("s2", new Student("B", 10)); //又新建一个mapsetValue方法:
setValue对ValueStack中存储元素值的修改操作:vs.setValue("name", "X");将栈中第一个name元素修改为X, 借用上面代码, 此处的修改是将"C"变为"X"setValue的第一个参数是一个OGNL表达式setValue对ActionMap中存储元素值的修改操作:vs.setValue("#name", "X");这里修改的name属性, 是对ActionMap中key为name的value进行修改
  1. ValueStack的findValue
    在JSP上使用OGNL表达式获取ActionMap或者ValueStack中的内容的时候, 都是执行如下操作
vs.findValue("name"); //在ValueStack中查找名为name属性的值
vs.findValue("#name"); //在ActionMap中查找key为name的value值

Struts中的EL

JSP中的EL表达式获取的是请求域中对象(page -> request -> session -> application)
Struts2的StrutsRequestWrapper对request重新做了封装, 对getAttribute进行改写, 当获取完request域中对象后, 会先去ValueStack, 然后是ActionMap中寻找需要的对象

Struts2对EL表达式进行了改写使得获取对象变为: page -> request -> ValueStack -> ActionMap -> session -> application

注: 当使用OGNL表达式查找属性值的时候, 如果写做< s:property value=“name” />, 它会先去ValueStack中查找, 当没找到的时候再去ActionMap中, name作为key找一遍.

Struts2中#, $, %的使用

  • #
OGNL表达中获取ActionMap中的Key为key的value值:<s:property value="#name"> //获取Key为name的value值创建Map对象的时候, 主要用于CheckBox, radio的多条件选择:<s:radio list="#{ 'male':'男', 'female':'女' }">
  • $
JSP中使用EL表达式:${name}
在xml中配置文件名, 或者使用静态函数(避免在JSP中写<%%>代码)${@java.lang.Math.random()}
  • %
强制将一个字符串看做是OGNL:<s:property value="%{name}">

Struts2中常用标签(使用OGNL配合使用)

  • iterator标签
    主要用于迭代遍历元素, 类似于JSP中的foreach标签, 下面举例说明:
Action类:
//使用list模拟从数据库提取Student数据, 显示在结果视图中public class DemoAction extends ActionSupport{private List<Student> students;public String findAll(){ //action方法students = new ArrayList<Student>(3);students.add(new Student("A", 20));students.add(new Student("B", 30));students.add(new Student("C", 10));return SUCCESS;}public List<Student> getStudents(){return students;   }public void setStudents(List<Student> students){this.students = students;}}
//JSP中iterator操作<s:iterator value="students" var="s" status="vs"><tr><td><s:property value="#vs.index"/><br/></td><td><s:property value="#s.name"/><br/></td><td><s:property value="#s.age"/><br/></td>    </tr></s:iterator>

注:

1.在遍历的过程中具有两种操作用于暂时存储需要遍历的变量(方便获取该变量的内部属性):a.使用ActionMap: 当指定在iterator中指定var属性的时候,Struts2会将var作为key, 当前变量作为value存入ActionMap中, 便于后面通过OGNL表达式获取该变量的内部属性, 因为key是固定的, 所以下一个元素存入ActionMap中会将上一个元素的value覆盖, 这样做也是为了减少空间占用,遍历结束后会将最后存在ActionMap中的变量removeb.使用ValueStack: 如果没有指定var, 那么Struts2会直接将该变量压入栈中, 当使用完该变量进行pop操作, 原因同上2.status主要是用来记录遍历的数据属性(以status作为key, 数据属性作为value存入ActionMap中):status具有index, count, odd, even, first, last属性, 表示下标, 遍历的数据和, 奇数位, 事件, 第一个值, 最后一个值, 具体用法自行百度3.在上面例子中, 可以使用value="name"的OGNL表达式来输出变量属性, 也可以使用EL表达式${name}来输出变量属性
  • set标签
    与JSP中的set标签一样, 就是声明一个变量, 然后对该变量赋值, 设置访问范围
<s:set value="a" var="1111" scope="session"/>
<s:property value="#1111"/>
声明一个变量"1111", 赋值为"a"的字符串, 设定访问范围为sessionset设置的变量是存入Map中的, value代表属性值, var代表Key值, scope取值范围application, session, request, page, action, 当scope不写的时候默认是action, ActionMap与request中各存一份
  • action标签
    在JSP中调用action方法: < s:action name=“action1” executeResult=“true”/> ,executeResult表示是否显示执行动作结果, 默认值false

  • url和a标签
    url标签主要用于获取url地址
    a标签用于向一个url地址进行跳转, 就< a href="…"/ >

例:<s:url action="action1" value="action1" var="url"><s:param name="username" value=" 'test' "></s:param></s:url>action: 获取值为action1的动作请求地址, 类似于EL表达式: ${pageContext.request.contextPath}/action1.actionvalue: url标签中的value用于输出value的值, 此时的value后面的参数不是OGNL表达式, 只是一个普通字符串; 而param中的value代表get方式添加参数, 会自动编码 如:username?test var: 将值为url作为key存入ActionMap中使用上面的url<a href="<s:property value='#url'>">点击</a>当使用<s:a>标签的时候就类似于使用<s:url>标签与<a>标签的结合品<s:a action="action1"><s:param name="username" value=" 'test' "></s:a>
  • if/else标签:
    if/else标签的用法与JSP中标签的用法一致
<s:if test=" name=='A' ">A</s:if>
<s:elseif test=" name=='B' ">B</s:if>
<s:else>C

防止表单数据重复提交

Servlet中的解决方式:

  • 用户第一次提交表单数据之前先将数据存入Session域中, 当用户数据提交之后就删除Session数据, 当用户重复提交的时候会发现表单中数据与Session中数据无法做比较, 最后判定数据重复提交, 对后面提交的数据不作处理

Struts2中的解决方式

  • 使用token/tokenSession拦截器(Struts2提供的一个拦截器)
使用token/tokenSession拦截器的时候, 会产生一个令牌隐藏在Session域中, 当用户提交数据后令牌消失, 下一次提交找不到对应的令牌, 所以最后判定为用户数据重复提交
如上面看到的, Struts2中防止重复提交与Servlet中防止重复提交的思想是一致的此处说明一个问题就是:token/tokenSession不在Struts2的defaultStack中, 在使用的时候需要配置defaultStack拦截器token与tokenSession的区别:token做拦截的时候, 当用户提交后有一个页面跳转, 有一个错误反馈, 告诉用户数据重复提交tokenSession做拦截的时候, 不去做页面跳转和错误反馈, 无论用户提交多少次表单数据, tokenSession只取第一次提交的数据

下面使用token举例说明(使用tokenSession的时候, 只需将token改为tokenSession):

index.jsp:<s:form action="save"><s:token></s:token> <%此标签用于生成隐藏令牌%><s:textfield name="name" label="用户名"></s:textfield><s:submit value="保存"></s:submit></s:form>Struts.xml:<struts><constant name="struts.devMode" value="true"></constant><package name="p1" extends="struts-default"><action name="save" class="com.action.DemoAction"><interceptor-ref name="defaultStack"></interceptor-ref><!--配置token拦截器--><interceptor-ref name="token"></interceptor-ref><result type="redirect">/success.jsp</result><!--使用token的时候必须做invalid.token跳转, 跳转到error.jsp中--><!--在使用tokenSession的时候不需要做invalid处理--><result name="invalid.token">/error.jsp</result></action></package></struts>

到此Struts2的学习就结束了, 在后面的学习中, 我会将一个没有讲到的内容以及一些容易犯错的地方补充上.

上面有错, 还请指出, 如果认为我写的还不错, 还请点个赞, 多多支持一下, O(∩_∩)O~~

Struts2_4_ActionMap与ValueStack详解_Struct2的EL及常用标签_防止表单数据重复提交相关推荐

  1. SVG 详解(四)其他常用标签

    文章案例 => 传送门 clipPath-裁剪 能限制哪些地方可见,哪些地方不可见.标记指定的区域之外的所有内容都不会被显示(图像不会被绘制出来).剪切路径是用clipPath元素定义的,属性c ...

  2. pillow属于python标准库吗_详解Python图像处理库Pillow常用使用方法

    PIL(Python Image Library)是python的第三方图像处理库,但是由于其强大的功能与众多的使用人数,几乎已经被认为是python官方图像处理库了. 其官方主页为:PIL. PIL ...

  3. 详解STS(SpringToolSuite)常用设置

    详解STS(SpringToolSuite)常用设置大全 STS常用设置详解 一.快捷键类设置 1.1.STS常用快捷键 1.2.常用编辑快捷键 1.3.查找和定位快捷键 1.4.调试快捷键 二.字体 ...

  4. ansible自动化运维详解(三)ansible常用模块续

    文章目录 ansible自动化运维详解(三)ansible常用模块续 四.ansible常用模块(2) 4.10.yum_repository 4.11.dnf 4.12.service 及 fire ...

  5. css sheet2.0,详解CSS3.0(Cascading Style Sheet) 层叠级联样式表

    CSS3.0(Cascading Style Sheet) 层叠级联样式表 快速入门: CSS01 h1 { color: red; } 标题一 CSS的三种导入方式: 行内样式(优先级最高,但不建议 ...

  6. java dfs算法蓝桥杯题_【蓝桥杯省赛JavaB组真题详解】四平方和(2016)_疼疼蛇的博客-CSDN博客...

    原文作者:疼疼蛇 原文标题:[蓝桥杯省赛JavaB组真题详解]四平方和(2016) 发布时间:2021-02-26 15:00:01 题目描述 四平方和 四平方和定理,又称为拉格朗日定理: 每个正整数 ...

  7. docker build命令详解_Docker镜像与容器常用命令图文详解

    一.系统命令 #查看docker版本 docker version #查看docker的系统信息,包含镜像容器的数量 docker info #查看docker的所有命令 docker --help ...

  8. linux电脑滚轮不能用,图文详解电脑鼠标滚轮不动了怎么办_电脑鼠标滚轮不能用的三种解决方法-系统城...

    近期,许多小伙伴发现电脑鼠标滚轮失灵了,无缘无故的就无法使用,浏览网页玩游戏都没办法继续进行,真的很麻烦.针对电脑鼠标滚轮不动了的故障,小编收集整理具体原因和解决方法给大家,希望大家采纳! 原因一:鼠 ...

  9. 【笔记】IP地址详解、Linux网络及常用命令

    IP地址 IP地址基本概念 IP地址(Internet Protocol Address)是指互联网协议地址,又译为网际协议地址.IP地址在网络层将不同的物理网络地址统一到了全球唯一的IP地址上(屏蔽 ...

最新文章

  1. 下一站,向冠军冲击!
  2. ystep jQuery流程、步骤插件
  3. Java中的数组怎么弄随机数_Java – 如何从值数组中创建随机数
  4. jsp中通过多种方式实现面包屑导航
  5. python变量定义必须赋值_Python3单行定义多个变量或赋值方法
  6. Java入参关键字_Java基础17-成员变量、return关键字和多参方法
  7. 安装oculus运行时出现问题_U盘安装windows10出现的问题解决方法
  8. 【Java数据结构与算法】第十七章 二分查找(非递归)和分治算法(汉诺塔)
  9. DeFi保险项目Bumper完成1000万美元私募轮融资
  10. smarty编译,缓存原理
  11. 基于贝叶斯网络模型的自适应测评
  12. 计算机扫描服务开启,win7系统,电脑打印机右键中无扫描选项(WIA已启动)
  13. Gradle基础:7:Property使用方式
  14. video标签和source标签
  15. [Unity]Mesh Baker3.1.0使用教程
  16. 《动手学深度学习》(PyTorch版)代码注释 - 32 【RNN_with_zero】
  17. Coursera机器学习+deeplearning.ai+斯坦福CS231n
  18. uni-app--》如何制作一个APP并使用?
  19. EXCEL批量替换公式数据变成真两位小数
  20. RXD's date

热门文章

  1. javax.net.ssl.SSLException MESSAGE: closing inbound before receiving peer‘s close_notify
  2. 服务器内存延迟,内存带宽、延迟性能测试
  3. python-kafka 常用 api 汇总
  4. android按钮固定尺寸,如何在android中保持按钮的固定宽高比
  5. 使用python3连接hiveserver2的方法
  6. mysql 表的存储类型_MySQL数据表存储引擎类型及特性
  7. 三种不使用中间参数,交换两个参数的值的方法
  8. c#利用定时器自动备份数据库(mysql)
  9. 康纳的表情包(思维)
  10. js for in 遍历对象与数组