servlet的api
ActionContext里面大多数是静态方法。我们可以通过getContext()的方法,去实例化它。然后可以通过getParameters()获取form表单传递的值。但是这个值是个map集合,需要迭代他。另外可以通过put,getSession,applicaton来往里面放值,相当于在request,Session,application里存放值。方法名字是叫完全解耦合的方法。不清除为什么这样就是解耦合的方式了。
另外是使用原生的servlet的API。struts2框架给我们提供了一个类是ServletAcionContext.里面有2个主要的方法是getRequest(),和getResponse()。两个方法。有了这两个方法,就可以在request,session,application。里存值和取值了。另外有了response对象,就可以做一些输出流了,比如ajax,下载,上传之类的。
总结下这里,ServletActionContext继承于ActionContext。刚刚查阅了下资料。说是尽量使用ActionContext。首先是继承关系,那么ActionContext有的方法。ServletActionContext也有。但是ActionContext封装了request,session,application的方法。获得是一个map集合。以键值对的形式来获取值,ActionContext封装了一些web的对象。就不用于底层的web进行打交道。让struts2的action和web解耦合。
配置和转发
这里首先讲的是global这个标签,这个标签在package包下。不属于任何action,在global这个标签里设置一个返回标志name。然后跳转的页面。说白了。就是这个标签可以让,在这个package包下,所有方法的返回值只要符合global里的name,都会跳转到global这个标签后的地址。但是也有例外,就近原则吧,如果是局部就设置了的话,那么就优先实现局部的方法
接下来就是页面的跳转问题了。在type里定义一些属性比如
dispatcher:是默认的从action转到jsp。
redirect:是action到jsp的重定向。
chain:是多个action之间的转发,从一个action跳到另外一个cation。
redirectAction:是多个action之间的重定向,也是从一个action到另外一个action.
stream:流的形式,用于下载,上传之类的。
数据的封装
首先需要灌输的理念是,当struts2接收到求情的时候,到处理请求,需要结果许多的过滤器,这些过滤器在struts2的架包核心包里就可以看到。包里有个struts-defult.xml的文件,里面就有说明过滤器,那么这些过滤器都是有作用的,有些是做数据转型的,有些是为了封装数据的,都是有这些过滤器的特定功能的,那么在封装的数据过程中,通过action类调用set方法,来给action类的成员变量赋值,这个是一个简单数据封装的概念。当然get方法也是不可或缺的,set方法相当于页面拿值,get方法相当于页面拿值。
struts2作为web层的框架之一,负责数据的传输是必要的责任,当然它也不负所望,提供了强大的数据封装功能。
其中有3种的数据封装方式,
1.直接通过成员变量的取值。
这种没有技术可以说,只要页面上的name和成员变量的名字,可以对得上,并且有set方法,那么就可以拿到值。
2.通过创建一个javabean类,在求情的action上实例话这个javabean。并且给它get和set方法,就可以了,当然页面上,需要主要,比如javabean的对象是user。对象里的成员变量有id。那么在页面是name=user.id。以这个样子的形式给javabean赋值。
3.模型驱动的一种方式,这种方式和第2种有点像,也是通过一个javabean。不同的是需要action去实现ModelDriven的接口。这个接口是有泛型的。需要穿件一个javabean写进去。那么这个javabean里的成员变量就是你要接收的值得了。这样看起来是不是和第2种方式很像?只是过程更加繁琐了,但是繁琐是有繁琐的好处的,通过实现这个ModelDriven接口,在页面上就不需要 【对象。成员变量】了,直接写对应的成员变量就可以了,这个样子可以说是在一定程度上,有了安全性。
另外说一些不常用的一些例子,就是在页面传输数据,到服务器的时候,有些时候需要集合,那么就有了这样的写法,
如果是list集合,那么就在页面上是name=list[0].id。这个样子就是list上面的0位置上传了。当然在服务器的action上面也要有集合的gei和set方法。
如果是map集合的话。页面是就定义了key值,name=map['key1'].id.那么就是这样,key1就是key值,后面id的值,就是values了。
拦截器
这里先说说过滤器和拦截器的区别。
拦截器不依赖servlet容器——过滤器依赖
拦截器是只拦截action请求——过滤器是任何请求都拦
在action的生命周期中拦截器可以被调用多次——过滤器只有在初始化的时候被调用一次。
拦截器可以访问action上下文,和值栈里的数据——过滤器不能访问呢。
这里就涉及到了aop思想和struts2的运行流程了,埋下一个坑,后面写两篇文章来讲。
那么这个的拦截的实现,我看过很多种写法有实现
第一种是实现接口
Interceptor。这个里面有3种方法。第一个关闭后,第二个是执行中,第三个是初始化tomcat执行的时候启动。
第二种方法是继承AbstractInterceptor这个抽象类,它是接口Interceptor的实现类,更加方便的是,在实现过滤器中不用像第一种方法那样,有3个方法了,主要过滤器的方法就是第二种ntercept()。在这里方法里做文章。
第三种方法是通过MethodFilterInterceptor的方法,这个类,是AbstractInterceptor的子类,默认的情况下拦截器是会拦截action的类,这里不包含get和set方法。这个时候就是可以使用这个MethodFilterInterceptor,方法过滤拦截器,可以实现某个方法的拦截,对action的拦截做细致化,而不是粗粒的实现拦截。(通过查阅资料,有疑问一个action类只能运行一个action的方法,这里提供了拦截多个action方法的机制有什么作用。看到下面有个游客的回答,我觉得应该是正确的答案了,这个机制,主要是针对通配符和动态执行的拦截。另外个游客也说明了在web。xml里设置拦截路径,那么在这个路径下所有的方法都会被拦截,不需要设置需要拦截哪个方法,只需要设置不需要拦截哪个方法。)
另外来说明下定义拦截器在配置文件中
这种是在直接设置了拦截器的类,直接引入,这里需要说明的是defaultStack这个默认的过滤需要加,因为在我们自定义了拦截器之后,默认的拦截器就失效了,我们需要手动去添加它。
还有一种通过拦截器栈的方式来写拦截器
这个更多是用户拦截器比较多的情况下,才使用它。
接下来就是拦截器的一些功能了,拦截器最经常使用的功能,是权限功能,是否登录了,那么这里简单说明下,加深下自己的记忆,百度的例子已经有非常多了。
1.首先在拦截器的方法中,是否能获取到session里的账号,如果不能取得那么就返回一个login
这个时候在配置文件里,设置一个全局的变量
如果为login就跳回登录界面。
2.之后因为拦截action方法,连登录的action都被拦截了,那么就需要在登陆的action下面设置不拦截登录的方法
excludeMethods就是不拦截的值,在
MethodFilterInterceptor的源代码里可以查找到这个成员变量。
最后需要提的是,如果是在子窗口登录的话,就一个大页面,包含了一个小页面。那么可以在form表达里设置target="_parent"打开是父级页面。
这里埋下了2个坑aop思想,和struts2的运行流程,运行流程这个的话会比较繁琐,要配合源代码讲,会理解的更好,aop思想的话,理解不深,就讲的比较简单了。