②.Struts2深入浅出-A.ppt_第1页
②.Struts2深入浅出-A.ppt_第2页
②.Struts2深入浅出-A.ppt_第3页
②.Struts2深入浅出-A.ppt_第4页
②.Struts2深入浅出-A.ppt_第5页
已阅读5页,还剩73页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第二节,Action,韩 冰 cris_,2,本章学习任务,Action 入门(3种Action测试) namespace命名空间 自定义Action 调用Action的自己方法 路径设置 通配符配置 接收用户输入信息(3种方式) 乱码问题解决 简单数据校验 action访问web元素 包含模块配置文件 默认action,2019/5/27,Action是什么?,在Struts2中,一个Action类代表一次请求或调用,每个请求的动作都对应于一个相应的Action类,一个Action类是一个独立的工作单元。 也就是说,用户的每次请求,都会转到一个相应的Action类里面,由这个Action类来进行处理,因此说一个Action类代表了用户的一次请求或调用。,换句简单的话来说,Action就是用来处理一次用户请求的对象。,2019/5/27,Action能干什么?,2019/5/27,Action能干什么?,根据上面的Action实现,你会发现,在Struts2里面,Action充当着MVC中模型的角色,也就是说Action既封装了业务数据,又要处理业务功能。当然,在实际的JavaEE开发中,逻辑部分会放到逻辑层去实现,这就演变成Action只是去调用逻辑层来进行业务逻辑的处理,并不是真的在Action里面去实现业务逻辑的处理。 上面这个Action的属性和属性对应的getter/settter方法,就是用来接收用户请求的数据,并把这些数据封装在Action中,在后续处理中可以访问这些数据。 再仔细察看上面Action的实现中的execute方法的实现,你会发现execute方法里面实现的功能,正是前面学习的MVC的控制器部分的功能。因此,从另外一个角度来说,Struts2的Action也充当着MVC中控制器的角色。,2019/5/27,Action的配置,不管Action采用何种实现方式,要正确运行,都需要在struts.xml中进行配置,这是使用Action的基础。 在前面LoginAction为例来看看Action的基本配置,复杂的配置在后面有详细介绍。,2019/5/27,Action的配置,2019/5/27,Action实现,在Struts2中,Action可以不实现任何特殊的接口或者继承特殊的类,仅仅是一个POJO(Plain Old Java Object,简单的Java对象)就可以,但是要有一个公共的为空参的构造方法,其实缺省的构造方法就可以,还要有一个execute方法,定义格式上图所示: 这个execute方法要求: 可见性为public 不需要传入参数 返回一个字符串,其实就是指示的下一个页面的result。 可以抛出Exception,当然也可以不抛例外,在实际开发的时候,通常会让Action实现Action接口或继承ActionSupport类。,2019/5/27,实现Action接口,就像在示例中一样,可以让我们自己写的Action类实现Struts2的Action接口。如: public class LoginAction implements Action /省略了 注意:在导入Action接口的时候,有好多同名不同包的类都叫Action,比如javax.swing.Action,一定要注意,我们需要使用Xwork2中的Action接口。 在Action接口中也仅仅定义了前面说的execute方法,除此之外,还有一系列预定义的字符串常量,这些常量可以用于返回一些预定的result,比如:,2019/5/27,Action常量,2019/5/27,继承ActionSupport类,由于Xwork的Action接口非常简单,为程序员提供的帮助有限,因此,在实际开发中,会更多的使用继承ActionSupport类来实现Action的方式,示例代码如下: import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport /省略了 ,2019/5/27,继承ActionSupport类,ActionSupport类本身实现了Action接口,所以继承ActionSupport类就相当于实现了Action接口。 除此之外,ActionSupport类还实现了其它几个接口,来为程序员提供更多使用的功能,比如: com.opensymphony.xwork2.Validateable:提供validate()方法来为Action增加验证的功能 com.opensymphony.xwork2.Validateaware:提供方法来保存和恢复action或field级的错误信息 com.opensymphony.xwork2.TextProvider:提供获取本地信息文本的功能 com.opensymphony.xwork2.LocaleProvider:提供getLocale()方法来获取本地消息 这些接口和Struts2的一些其他特性相结合,可以实现基本的数据验证功能和国际化。更多关于数据验证和国际化的知识,以后有专门的章节去讲解。,2019/5/27,Action的数据,在示例里面,在运行Action的execute方法的时候,你会神奇般的发现,Action的属性是有值的,而这正是Action进行请求处理所需要的数据。那么,这些数据从何而来呢? 很明显,这些数据就是你在登录页面填写的数据,换句话说,这些数据来源于用户请求对象,也就是request对象。 可是,Struts2怎么知道,页面上的值如何和Action的属性进行对应呢? 这就涉及到如何把页面的数据和Action进行对应的问题了,接下来就来讨论页面的数据和Action的三种基本对应方式。,2019/5/27,Action基本的数据对应方式,在Struts2中,页面的数据和Action有两种基本对应方式,分别是:属性驱动(FieldDriven)和模型驱动(ModelDriven)。 属性驱动又有两种情况:一种是基本数据类型的属性对应;另外一种是JavaBean风格的属性对应。为了区分它们,我们约定称呼如下:称呼“基本数据类型的属性对应”为属性驱动,而“JavaBean风格的属性对应”为直接使用域对象。 下面就分别来看看它们都什么意思,都如何实现。,2019/5/27,1.属性驱动FieldDriven(基本数据类型的属性对应),基本数据类型的属性对应,就是web页面上要提交的html控件的name属性,和Action的属性或者与属性相应的getter/setter相对应,这种做法就是基本数据类型的属性对应的属性驱动。 事实上,我们已经使用过这种方式了,前面示例,就是采用的这种方式来把值对应到Action中的。 比如在登录页面上,我们是这么写的: 账号: 密码: ,2019/5/27,1.属性驱动FieldDriven(基本数据类型的属性对应),在Action中是这么写的: public class HelloWorldAction extends ActionSupport private String account; private String password; /省略getter和setter方法 /其他部分暂时省略掉,好让大家看清楚数据的对应关系 ,2019/5/27,1.属性驱动FieldDriven(基本数据类型的属性对应),你会发现,在页面上input的name属性,和Action的属性是同一个名称,这样一来,当页面提交的时候,Struts2会自动从request对象里面把数据取出来,然后按照名称进行对应,自动设置到Action的属性里面去。 有些同学可能会说,Action的属性都是private的呀,按道理外部是无法访问的,正是因为如此,才为每个私有的属性提供了getter/setter方法,来让外部访问。 这也意味着,如果你不想为每个属性提供getter/setter方法,觉得很累赘,有一个简单的方式,那就是把属性的可访问权限设置成public的就可以了。但在Java开发中,不是很建议直接开放属性让外部访问,一般都是通过getter/setter方法来访问。当然如何选择,根据实际情况来判断吧,总之两种方式都是可以把值对应上的。,2019/5/27,2:属性驱动FieldDriven(直接使用域对象),仔细察看上面属性驱动的方式,会发现,要是需要传入的数据很多的话,那么Action的属性也就很多了,再加上对应的getter/setter方法,Action类就直接上百行了,再在里面写请求处理的代码,会显得Action非常零乱,不够简洁,而且给人的感觉是Action的功能也不够单一。那么该怎么解决这个问题呢? 很简单,把属性和对应的getter/setter方法从Action里面移出去,单独做成一个域对象(二期学过的实体Bean),这个对象就是用来封装这些数据的,然后在Action里面直接使用这个对象就可以了,2019/5/27,2:属性驱动FieldDriven(直接使用域对象),(1)先看看域对象的写法,按照JavaBean的风格来写,示例代码如下: public class User private String account; private String password; /省略getter和setter方法 ,2019/5/27,2:属性驱动FieldDriven(直接使用域对象),(2)看看此时,Action写法的变化,主要就是直接使用这个对象,其实就是定义一个属性是这个对象类型,然后为这个属性提供相应的getter/setter方法即可,当然也可以直接把这个属性的可访问属性设置成public,这样就不需要写getter/setter方法了。 原来Action里面直接使用属性值的地方,就修改成使用这个属性对象来获取值了。示例代码如下:,2019/5/27,2:属性驱动FieldDriven(直接使用域对象),public class LoginAction extends ActionSupport private User user= new User(); public User getUser() return user; public void setHwmUser user this.user = user; ,2019/5/27,2:属性驱动FieldDriven(直接使用域对象),public String execute() throws Exception /1:收集参数,不用做了,数据会直接映射到上面的hwm里面 /2:组织参数,也不用作了,数据会映射到上面的hwm的时候,就已经组织好了 /3:调用模型的逻辑功能处理,这里不需要,只是简单的输出一下传入的参数 this.businessExecute(); /4:根据逻辑处理的结果来选择下一个页面,这里直接选择转向欢迎页面 return “success“; /* * 示例方法,表示可以执行业务逻辑处理的方法, */ public void businessExecute() System.out.println(“用户输入的参数为=“+“account=“+user.getAccount()+“,password=“+user.getPassword(); ,2019/5/27,2:属性驱动FieldDriven(直接使用域对象),(3)Action发生变化后,登录页面上也需要相应改变,否则数据是无法正确对应的,主要是在相应的name属性上,添加一个域对象的前缀,指明这个值到底对应到哪一个域对象里面去,示例如下: 账号: 密码: ,2019/5/27,2:属性驱动FieldDriven(直接使用域对象),(3)Action发生变化后,登录页面上也需要相应改变,否则数据是无法正确对应的,主要是在相应的name属性上,添加一个域对象的前缀,指明这个值到底对应到哪一个域对象里面去,示例如下: 账号: 密码: 同理欢迎页面也需要相应调整,示例如下 测试数据标签 欢迎账号为的朋友来访,去测试看一看吧!祝福你哟!,2019/5/27,3.模型驱动ModelDriven,在Struts2中,还有另外一种对应数据的方式叫模型驱动ModelDriven。它的基本实现方式是让Action实现一个ModelDriven的接口,这个接口需要我们实现一个getModel()的方法,这个方法返回的就是Action所使用的数据模型对象。 (1)把Action代码修改成ModelDriven的实现方式,只是添加了ModelDriven的实现,另外去掉了“user”属性对应的getter/setter方法,其他地方基本上没有什么变化,示例代码如下:,2019/5/27,3.模型驱动ModelDriven,import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.ModelDriven; public class LoginAction extends ActionSupport implements ModelDriven private User user = new User(); public Object getModel() return user; public String execute() throws Exception this.businessExecute(); return “success“; /* * 示例方法,表示可以执行业务逻辑处理的方法, */ public void businessExecute() System.out.println(“用户输入的参数为=“+“account=“+user.getAccount()+“,password=“+user.getPassword(); ,2019/5/27,3.模型驱动ModelDriven,(2)登录页面也需要做相应调整,主要就是去掉刚才给name属性添加的“user.”这个前缀,示例代码如下 账号: 密码: 同理去调整欢迎页面,这里就不去示范了。,那么这里为什么不需要前缀了呢?,2019/5/27,3.模型驱动ModelDriven,原因很简单,使用ModelDriven的方式,一个Action只能对应一个Model,因此不需要添加前缀,Struts2就能够知道,页面上“account”的值就对应到这个Model的“account”属性。如果你去加上前缀,反而对应不上了。,2019/5/27,1)这里学习了三种数据的对应方式,在实际开发中该如何选择呢? 下面简要分析一下: 属性驱动(基本数据类型的属性对应): 优点:简单,页面name和属性直接对应; 缺点:导致Action类看上去比较零乱,显得功能不够单一。因此在实际开发中会酌情使用。 属性驱动(直接使用域对象): 优点:把模型数据从Action中分离出来,让Action专注于请求处理,使得程序结构更清晰; 缺点:页面上在对应的时候,必须添加正确的前缀,稍嫌麻烦。 但正是因为有前缀,在一个Action有多个数据模型的时候,这个缺点反而变成了优点,因为可以根据前缀来区分到底把这个数据对应给谁,这样一来,就不会乱了,比如:“hwm.uuid”、“um.uuid”就表示hwm和um这两个模型里面都有一个uuid的属性,但是,现在是带着前缀来指定值的对应,就不会出错了。在实际开发中,推荐优先使用这个方式。 模型驱动: 优点:把模型数据从Action中分离出去了,使得程序结构更清晰; 缺点:需要Action实现特殊的接口,而且把模型数据和Action作了一个绑定,这极大地限制了一个Action对应多个数据模型的能力,当然也可以做到,就是在这个模型里面包含其他的数据模型。在实际开发中,根据情况来选用。,2019/5/27,小结:扩展问题,事实上,这三种方式是可以混合使用,甚至是三种方式一起使用。但是属性驱动(基本数据类型的属性对应)和模型驱动是有可能冲突的,因为这两种对应方式都没有前缀,如果出现这种冲突的情况,那么优先模型驱动的对应方式。 还是举个例子来说明,如果在Action中同时出现三种方式,示例代码如下:,2019/5/27,小结:扩展问题,public class LoginAction extends ActionSupport implements ModelDriven /* * 用于ModelDriven使用 */ private Useruser = new User(); /* 用于域对象的方式使用 */ public User user2 = new User(); /* * 用于FieldDriven使用 */ public String account = “; public Object getModel() return user; public String execute() throws Exception System.out.println(“模型驱动的值:account=“+user.getAccount()+“,password=“+user.getPassword(); System.out.println(“使用域对象的值:account=“+user2.getAccount()+“,password=“+user2.getPassword(); System.out.println(“属性驱动的值:account=“+account); return “success“; ,2019/5/27,小结:扩展问题,此时登录页面修改成如下示例: 账号: 密码: 注意,在上述页面的写法中,name=“submitFlag“的值,将会使用ModelDriven的方式对应,因为没有其他可供它对应的地方;name=“account“的值,既可以对应到Action的account属性,也可以通过ModelDriven的方式对应到user的account属性;而name=“user2.password“的值,只能按照域对象对应的方式,对应到user2里面的password属性去,2019/5/27,小结:扩展问题,去运行一下,看看结果。结果示例如下: 模型驱动的值:account=test,password=null,submitFlag=login 使用域对象的值:account=null,password=test,submitFlag=null 属性驱动的值:account= 你会发现,password直接对应到了域对象的password去,毫无争议;而account的值,虽然可以同时对应到模型和属性上,但结果很明显是模型驱动优先,也就是对应到模型的account属性去了。,2019/5/27,的配置,通过上面的示例可以看出,Action需要在struts.xml中配置才可以使用,而且Action应该配置成为元素的子元素,那么元素的功能是什么呢? 元素可以把逻辑上相关的一组Action、Result、Intercepter等元素封装起来,形成一个独立的模块,package可以继承其他的package,也可以作为父包被其他的package继承,比如前面示例中配置的“”,loginAction这个包就继承了struts-default这个包。 元素有如下属性: name:包的名称。必须配置 extends:要继承的包,后面配置的是被继承的包的名称。可选 namespace:包的命名空间。可选 abstract:定义包为抽象的,也就是不能包含Action的定义。可选,2019/5/27,pageage属性- namespace,namespace配置的是包的命名空间,同一个命名空间里面不能有同名的Action,当然不同的命名空间里面是可以有同名的Action的。类似于Java的包的功能,namespace可以有效的防止action重名的冲突,因为配置了namespace后,在访问action的时候就需要添加namespace来作为action的前缀。 如果不配置namespace,表示是默认的namespace,那么访问的时候不需要添加namespace前缀。比如前面的示例,struts.xml的配置如下:,路径设置问题,2019/5/27,pageage属性- namespace, /welcome.jsp ,2019/5/27,路径设置问题,2019/5/27,的配置,虽然Action在Struts2的开发中非常重要,但是其配置非常简单,基本的规则如下: 元素是元素的子元素,应该配置在元素里面 元素通常需要配置name和class属性,其中name是必须的 元素可以包含其他的子元素:比如、 基本的配置示例前面已经有了,通常也就是配置name和class属性,然后配置子元素,这里就不去赘述,而更多的配置在后面用到再讲。,2019/5/27,DMI(了解即可),直接演示,2019/5/27,的配置,虽然Action在Struts2的开发中非常重要,但是其配置非常简单,基本的规则如下: 元素是元素的子元素,应该配置在元素里面 元素通常需要配置name和class属性,其中name是必须的 元素可以包含其他的子元素:比如、 基本的配置示例前面已经有了,通常也就是配置name和class属性,然后配置子元素,这里就不去赘述,而更多的配置在后面用到再讲。,2019/5/27,分模块配置方式,在多人协作开发的团队中,配置文件如何组织至关重要。如果配置文件过少,会出现多人争用一个文件,造成大家互相等待,影响开发效率。如果配置文件过多,动辄几十上百个配置文件,这也会造成维护的困难,从而影响到开发的效率。 因此,如何划分配置文件的大小就显得尤为重要。在Struts2的开发中,struts.xml这个配置文件就是大家经常争用的核心配置。 通常,一个项目会根据业务的不同来划分出不同的模块,一个模块会由几个人协作开发,在模块内大家联系紧密,但是在模块间相互联系就会比较松散。因此,在划分配置文件的时候,一种常见的情况就是按照模块来划分。,2019/5/27,(1)现在,简单回顾一下项目中的struts.xml。, /welcome.jsp ,2019/5/27,(1)现在,简单回顾一下项目中的struts.xml。,这个配置文件的根元素是,它下面有三个常量配置元素和一个元素,而一个元素下有一个元素。现在关心的是action在项目中如何划分,所以抛开常量配置元素不看。其余的元素之间关系是: 一个元素可以有多个子元素。 一个元素可以有多个子元素。 按照项目的组织形式来类比,这里的元素就好比代表项目,而元素就是好比是业务模块,而元素就相当于是某个模块中的组件。 这样一来,就可以按照业务模块来组织我们的action了,也就是同一个模块的action配置在同一个包里面。 由于一个项目会有多个业务模块,也就是会有多个,如果所有的都配置在一个struts.xml文件里面,必然会引起大家争用这个配置文件,因此,在实际开发中,通常都是一个放在一个单独的文件中,比如叫struts-xxx.xml,最后由struts.xml来引用这些struts-xxx.xml。,2019/5/27,(1)现在,简单回顾一下项目中的struts.xml。,(2)比如一个电子商务的项目,分成饭店管理模块和入境管理模块。那么,饭店管理模块会单独有一个struts-hotel.xml,而入境管理模块会单独有一个struts-inbound.xml,最后由struts.xml来引用它们。 此时struts.xml的代码示例如下:,2019/5/27,2019/5/27,通配符配置,在以前的学习中,元素的配置,都是用明确的配置,其name、class等属性都是一个明确的值。 其实Struts2还支持class属性和method属性使用来自name属性的通配符,method属性是用来指示一个Action中的方法,这个方法会在执行Action的时候执行,也就是说,你配置了method属性,Action运行的时候会执行这个方法而不是execute方法,这个在后面会有详细讲述和示例。 (1)接下来看看使用通配符的示例,如果我们使用以下配置:,2019/5/27,通配符配置, /welcome.jsp 在上面的配置中: name属性的值中“*”代表长度不为0的任意字符串,因此,它可以响应的action只需要名称中间有一个下划线即可。比如页面可访问的action名称为:User_create.action、User_update.action等等。 在name属性定义了通配符之后,class属性使用第一个通配符(使用1作为占位),method属性使用第二个通配符。 如果使用User_create.action作为访问的action名称的话,struts.xml中action名称为User_create,第一个通配符匹配User,第二个通配符匹配create。因此,由com.shxt.action.UserAction的create方法来响应。,2019/5/27,通配符配置,package com.shxt.action.action; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport private String account; private String password; public String create() System.out.println(“哈哈,访问到create方法了,account=“+account); return “toWelcome“; public String execute() throws Exception System.out.println(“访问到execute方法了,account=“+account); return “toWelcome“; /属性对应的getter/setter方法,省略了 ,2019/5/27,通配符配置, 账号: 密码: ,2019/5/27,特殊实验,(2)在使用通配符的时候,也有可能不只一个使用通配符的元素可能匹配这次URL的访问,看以下的配置文件: /welcome.jsp /s2impl/welcome.jsp ,2019/5/27,特殊实验-说明,这时候,如果访问“User_create.action”,Struts2首先会查找是否有精确匹配的元素,这时候无论以上元素以什么顺序出现,Struts2肯定会先找到并使用精确匹配的元素。但是,如果没有精确匹配的元素,则Struts2会找到第一个匹配的使用通配符的元素来使用。 通配符对于那些简单的CRUD的工程或软件原型来说,只要Action的包名、Action的类名、对应的方法名写的有规律的应用,能大大简化配置的工作。,2019/5/27,默认类配置方式,在配置struts.xml的时候,对于元素来说,name属性是必须的,class属性是可以省略的,class属性的默认值是“com.opensymphony.xwork2.ActionSupport”。 以前配置的元素都是有class属性的,现在就来探究一下为什么可以不写class属性,以及在什么情况下可以不写。,2019/5/27,Action的生命周期,Struts2的Action的生命周期是:Struts2为每个请求都重新初始化一个Action的实例。可以稍微改造一下代码来验证一下。 1:给UserAction加上一个public无参的构造方法,在里面输出一句话。 大家都知道,一个Java类如果没有写构造方法,那么会有一个默认的public无参的构造方法,这里只是把它明确的写出来了,因此这么做,并没有改变Action的任何功能,只是想看一下到底什么时候,Action会被初始化。示例代码如下: public UserAction() System.out.println(“UserAction被初始化“); ,2019/5/27,Action的生命周期,2:然后在execute方法上也加入一个打印Action自己这个对象实例的语句,示例代码如下 public String execute() throws Exception System.out.println(this); this.businessExecute(); return “toWelcome“; ,2019/5/27,Action的生命周期,接下来按照如下顺序操作: (1)访问http:/localhost:8080/struts2/login.jsp,在页面上填写账号和密码,然后点击提交按钮,会跳转到欢迎页面。 这个时候去察看后台的输出信息,如下: UserAction被初始化 com.shxt.action.UserAction922804 用户输入的参数为=account=test,password=111111,2019/5/27,Action的生命周期,大家都知道在Java基础知识里面,“System.out.println(this);”这句话,在打印一个对象实例的时候,实际上是调用的这个类的toString方法,但是UserAction类没有实现toString方法,所以,会调用到Object的toString方法。Object的toString方法会打印出自己的全类名和Object的hashcode方法的返回值,这个hashcode方法返回一个数字,只要这个数字不同,则被打印的对象就绝不是同一个对象。 修改做完之后,重新启动Tomcat,仔细察看后台的输出信息,你会发现启动的时候,并没有打印出来那句“UserAction被初始化”,这说明了Action的初始化并不是在Tomcat启动的时候进行的。,2019/5/27,Action的生命周期,(2)接下来,按F5来刷新这个欢迎页面,会弹出如下页面:,2019/5/27,Action的生命周期,点击重试按钮,这样就相当于再次访问UserAction,再察看后台的输出信息,如下: UserAction被初始化 com.shxt.action.UserAction922804 用户输入的参数为=account=test,password=111111 UserAction被初始化 com.shxt.action.UserAction922804 用户输入的参数为=account=test,password=111111,2019/5/27,Action的生命周期-重要说明,“UserAction被初始化”这句话被打印了两次,说明UserAction对象的构造方法被调用了两次。 而且两次打印的toString分别是“com.shxt.action.action.UserAction922804”和“com.shxt.action.action.UserAction18e8541”,这说明了为两次web请求服务的UserAction对象不是同一个。 因此请记住,Struts2中的Action在每一次web请求的时候都要新建一个实例,在以后Struts2和Spring组合开发的时候还会提到这一点。,2019/5/27,Action的生命周期-重要说明,“UserAction被初始化”这句话被打印了两次,说明UserAction对象的构造方法被调用了两次。 而且两次打印的toString分别是“com.shxt.action.action.UserAction922804”和“com.shxt.action.action.UserAction18e8541”,这说明了为两次web请求服务的UserAction对象不是同一个。 因此请记住,Struts2中的Action在每一次web请求的时候都要新建一个实例,在以后Struts2和Spring组合开发的时候还会提到这一点。,2019/5/27,在Action中访问Servlet API实现,2019/5/27,2019/5/27,扩展一: ActionContext和ServletActionContext,ActionContext是Action执行时的上下文,里面存放着Action在执行时需要用到的对象,我们也称之为广义值栈。 Struts2在每次执行Action之前都会创建新的ActionContext,在同一个线程里ActionContext里面的属性是唯一的,这样Action就可以在多线程中使用。,2019/5/27,扩展一: ActionContext和ServletActionContext,1:ActionContext的线程安全性 那么Struts2是如何保证ActionContext的线程安全性呢? 看看ActionContext对象的代码,示例如下:,ThreadLocal又称为“线程局部变量”,它为每一个使用该变量的线程都提供一个变量值的 副本,使每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。 存放在ActionContext里的数据都存放在这个ThreadLocal的属性中, 而这个属性只会在对应的当前请求线程中可见,从而保证数据是线程安全的。,2019/5/27,扩展一: ActionContext和ServletActionContext,2:访问的是Map 在使用ActionContext来访问Session中数据的程序,你会发现,其实在程序里面访问的是一个Map,而非HttpSession对象,这是为什么呢? 原来,Struts2框架将与Web相关的很多对象重新进行了包装,比如将HttpSession对象重新包装成了一个Map对象,里面存放着Session中的数据,提供这个Map给Action使用,而不用Action直接和底层的HttpSession打交道。也正是因为框架的包装,让Action可以完全的和Web层解耦。,2019/5/27,扩展一: ActionContext和ServletActionContext,但是要注意一点,ActionContext不能在普通的Java应用程序中使用。 在以前的学习中,介绍了Action和Servlet API是解耦的,因此可以在Java应用程序中调用Action的execute方法来进行测试。但是如果使用了ActionContext来获取session数据,那么就不能这样运行了。因为ActionContext包装的都是Web的数据,在Java应用程序中运行的时候,没有Web的环境和响应的数据,因而会抛出空指针的异常。 访问其它的Web对象的值也是与此类似的,你通过ActionContext去访问的都是包装后的Map。,2019/5/27,扩展一: ActionContext和ServletActionContext,3:使用SessionAware接口 Struts2还提供另外一种简单的方式,使用SessionAware接口来访问存储于ActionContext中的数据,该接口通过使用IoC/DI来为Action注入Session Map,就可以在程序里面直接使用这个Map来操作数据了。 (1)在Action中不再需要访问ActionContext了,取而代之,Action实现SessionAware接口,该接口告知Struts2在Action执行之前要设置Session Map,是通过servletConfig 拦截器来实现的,这个拦截器在defaultStack里面就有。示例代码如下:,2019/5/27,扩展一: ActionContext和ServletActionContext,在上面的代码中: Action类实现SessionAware接口 这个接口要求Action类实现一个方法setSession(Map session), 通过这个方法注入Session的数据 在execute方法中, 通过这个私有属性就可以操作会话中的数据, 注意一点,这个Map中的值也是与HttpSession联动的。,注意可以做封装ActionSuppot,2019/5/27,扩展一: ActionContext和ServletActionContext,(2)结果界面也稍作修改,好来看出Action操作session后的效果,示例如下: 会话中的值: 通过Servlet的Api获取会话中的值:,2019/5/27,扩展一: ActionContext和ServletActionContext,为了能够在普通的Java应用中运行并测试Action,推荐大家使用SessionAware的方式来访问HttpSession。因为这样一来,在通过main方法运行或测试的时候,可以直接调用setSession方法,传入模拟的会话数据,就不会出现execute方法中抛出空指针的异常了。 因此,推荐大家使用SessionAware的方式来访问HttpSession。,2019/5/27,扩展一: ActionContext和ServletActionContext,4:使用其它包装接口 跟SessionAware类似,你可以使用RequestAware来获取包装请求对象的attribute中的值的Map;使用ApplicationAware来获取包装ServletContext对象的attribute中的值的Map;使用ParameterAware来获取包装请求对象的参数中的值的Map,等等,这里只罗列这几个常见和常用的,还有更多的请参见Struts2的API文档。,2019/5/27,扩展一: ServletActionContext,在实际应用开发中,光是获取数据就够了吗?答案显然是否定的,有些时候,根据功能需要,在Action中必须要能获取到Servlet相关的API,比如要操作Cookie。这个时候,就需要用ServletActio

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论