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

接着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~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/468702.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python快递代取系统_代取快递的变现方式,校园跑腿的经营范围有多大?

原标题&#xff1a;代取快递的变现方式&#xff0c;校园跑腿的经营范围有多大&#xff1f;进入大学&#xff0c;随着越来越多的学生加入到网购的行列。快递在学校也是堆积成山&#xff0c;高校校园快递市场也日渐红火。但往往带来的也有更多的麻烦&#xff0c;学生取快递时间变…

java 空指针异常之一。 新建的一个对象没有NEW 导致其SET属性时报错

代码&#xff1a; //会报错 Lendbook lbk;//不会报错 Lendbook lbknew Lendbook();//在这里报错lbk.setLenddate(new Date());lbk.setPersoncode(personcode);lbk.setPersonname(personname); 转载于:https://www.cnblogs.com/Ychao/p/6811648.html

我的互助小蜜圈

写在前面 从不久之前到现在&#xff0c;我的微信公众号从一个小小小阶段到了另一个小小阶段&#xff0c;非常感谢各位读者对我的信任和支持&#xff0c;当然我也是非常用心的维护这这群大佬&#xff0c;时刻想着怎样给各位大佬做好服务 &#xff0c;比如我正在溜娃&#xff0c…

设计模式_3_建造者模式

建造者模式(BuilderPattern) 内在的核心问题就是: 使用多个简单对象根据一种组合关系构造一个我们想要的复杂对象, 属于创建型模式 建造者模式的角色关系 建造者模式中总共有两种角色: 1.建造者: 负责建造每个基本组件 2.指挥者: 将建造者建造好的基本组件按照某种组合关系进…

比较两个表格的不同_两表数据的核对,WPS表格似乎更加方便容易

在EXCEL中的两个表格的数据对比&#xff0c;可能使用的方法会采用到查询语句&#xff0c;VBA之类的。显得在使用的过程显得有些复杂。在不经间发现WPS表格的功能处理此类的问题显得就比较的简单的多。查看并标识出分数相同的内容如下面的分数表&#xff0c;选择分数栏的范围&am…

6递归

1 /*2 递归函数:3 函数自己调用自己就叫递归函数4 递归可以实现循环5 递归是神,迭代是人(迭代循环)6 缺点:需要暂存大量的数据,递归次数太多会占用大量内存空间7 8 递归和迭代的区别9 迭代是循环结构 10 递归是选择结…

我的知识小密圈

写在前面从不久之前到现在&#xff0c;我的微信公众号从一个小小小阶段到了另一个小小阶段&#xff0c;非常感谢各位读者对我的信任和支持&#xff0c;当然我也是非常用心的维护这这群朋友&#xff0c;时刻想着怎样给大家做好服务 &#xff0c;比如我正在溜娃&#xff0c;隔断时…

设计模式_4_原型模式(对象的拷贝)

原形模式(PrototypePattern, 创建型模式,创建重复对象且保证性能, 对象的克隆) 通常使用原型模式创建一个原型接口, 用于获取创建对象的克隆, 对于浅拷贝与深拷贝不用纠结, 他们二者的区别就在于重写Clonable的clone方法 浅拷贝与深拷贝 浅拷贝: 直接调用Object的clone pub…

vk_down 每次下翻丙行 c++_笔记本接口不够用?不妨试试这款Type-C拓展坞,给你7个接口用...

随着笔记本电脑越来越轻薄化&#xff0c;已经很难再布局较多的数据接口了&#xff0c;但是在办公等环境下总是需要这些接口来满足需求。就拿小新个人来说&#xff0c;使用的是小米笔记本12.5寸款的&#xff0c;该款笔记本仅有三个接口&#xff0c;分别是全功能 USB-C 接口 x 1、…

学习,才是最好的投资~

推荐语&#xff1a;我因为王小波常说而喜欢的英国哲学家罗素的一句话&#xff1a; 参差多态乃是幸福的本源。正是因为有了多种多样的行业&#xff0c;才使得我们的职业也是多种多样&#xff0c;行行出大牛&#xff01;这个世界天生就注定有人搞互联网的&#xff0c;Linux&#…

第二百四十八节,Bootstrap轮播插件

Bootstrap轮播插件 学习要点&#xff1a; 1.轮播插件 本节课我们主要学习一下 Bootstrap 中的轮播插件。 一&#xff0e;轮播 轮播插件就是将几张同等大小的大图&#xff0c;按照顺序依次播放。 基本实例。 第一步&#xff0c;给轮播器区域div设置一个id给轮播器区域div设置样…

设计模式_4_适配器模式(AdapterPattern, 多个功能的结合)

适配器模式(AdapterPattern, 结构型模式) 用最通俗的讲法就是: 将多个功能相关或不相关的接口( 你需要的接口 )放到同一个实现类里, 构造一个具有多工功能, 多特点的"异类对象" 定义 是作为多个接口之间的桥梁,结合多个独立的接口(将多个类/功能结合在一起,构建出一…

xgboost分类_XGBoost(Extreme Gradient Boosting)

一、XGBoost在Ensemble Learning中的位置机器学习中&#xff0c;有一类算法叫集成学习&#xff08;Ensemble Learning&#xff09;&#xff0c;所谓集成学习&#xff0c;指将多个分类器的预测结果集成起来&#xff0c;作为最终预测结果&#xff0c;它要求每个分类器具备一定的“…

Android技术架构演进与未来

本文阅读大约需15分钟 引言众所周知&#xff0c;Android是谷歌开发的一款基于Linux的开源操作系统&#xff0c;每年迭代一次大版本升级。 小米、华为、OPPO、VIVO、三星等各大厂商对Android原生系统进行二次开发衍生出具有各家特色的系统&#xff08;比如MIUI&#xff09;&…

Sublime Text 3插件安装方法

一&#xff1a;安装Sublime Text 3插件的方法安装package control组件&#xff0c;然后直接在线安装&#xff1a;1、按Ctrl调出console&#xff08;注&#xff1a;安装有QQ输入法的这个快捷键会有冲突的。输入法属性设置-输入法管理-取消热键切换至QQ拼音&#xff09; 2、粘贴下…

Hibernate_1_配置文件详解_基础案例_Hibernate工具类_API详解_持久化类编写规则

Hibernate( ORM框架 ) Hibernate是一个数据持久化层的ORM框架. 它通过JavaBean, 数据库中的表与自身的映射关系达到表中数据的增删改查 特性 1.对JDBC访问数据库的代码进行封装, 简化数据访问的重复性代码 2.使用反射机制完成对Bean的封装 3.轻量级框架,支持关系型数据库 核…

建筑电气工程设计常用图形和文字符号_建筑水电图纸看不懂?10年老师傅教你看图技巧,分分钟安排...

1、建筑给排水工程包括&#xff1a;给水、排水、热水、消火栓、自动喷淋等常用系统&#xff0c;其管道当中流动的是水。(其管道输送介质为水)2、给排水系统的主要功能&#xff1a;(1)建筑给水系统的任务&#xff0c;就是经济合理地将水由室外给水管网输送到装置在室内的各种配水…

Android系统架构开篇

Android系统庞大且错综复杂&#xff0c;Gityuan带领大家初探Android系统整体架构&#xff0c;一窥其全貌。一、引言本文作为Android系统架构的开篇&#xff0c;起到提纲挈领的作用&#xff0c;从系统整体架构角度概要讲解Android系统的核心技术点&#xff0c;带领大家初探Andro…

20155220 实验三 敏捷开发与XP实践 实验报告

20155220 实验三 敏捷开发与XP实践 实验报告 实验内容 XP基础XP核心实践相关工具实验要求 没有Linux基础的同学建议先学习《Linux基础入门&#xff08;新版&#xff09;》《Vim编辑器》 课程完成实验、撰写实验报告&#xff0c;实验报告以博客方式发表在博客园&#xff0c;注意…

Hibernate_2_Hibernate中对象状态及转化_一级缓存_Session详解_HQL/SQL/Criteria_一对多关系_级联操作

Hibernate中的对象状态 在Hibernate中持久化对象具有三种状态: 瞬时态, 持久态, 游离态. 瞬时态: 对象没有与Hibernate产生关联(transient,session中没有缓存), 数据库中也没有对应记录> 对象无id, 没有关联 持久态: 对象与Hibernate产生关联(persistent, session中有缓存…