Struts2(二)

1.访问ServletApi三种方式


1).在Action访问Servlet API:

在Action类中操作Servlet中相关的对象(request,repsonse,session,cookie等)

  • 获取请求参数: request.getParameter(String ..)
  • 设置/获取共享数据: 域对象.setAttribute(String name,Object val);
  • 操作Cookie: response.addCookie(...);

2).Action访问Servlet API,有三种方式:

1.通过Action实现感知接口.

操作步骤:

  • 1):实现对应的感知接口.
  • 2):覆盖接口中对应的setter方法.
  • 3):定义成员变量接受setter方法中的参数.
  • 4):使用对象.

原理:拦截器.
常用的感知接口:
ServletRequestAware ---->感知request对象.
ServletResponseAware---->感知response对象.
ServletContextAware----->感知application对象.

2.使用ServletActionContext类.

好比是一个工具类,封装当前请求的对象和响应对象信息.
ServletActionContext类提供了很多静态方法,可以直接获取request/response等对象.

常用的方法:
static HttpServletRequest getRequest() :获取请求对象
static HttpServletResponse getResponse() :获取响应对象
static ServletContext getServletContext() :获取应用对象

Struts2(二)_第1张图片
Paste_Image.png
3.使用ActionContext类.

ActionContext:Action的上下文对象(环境).封装了当前请求/响应的所有的数据.

获取ActionContext对象:

    ActionContext ctx = ActionContext.getContext();
Struts2(二)_第2张图片
Paste_Image.png
Struts2(二)_第3张图片
Paste_Image.png
Paste_Image.png

3).Action访问Servlet API,有三种方式对比和选择:

  • 1.通过Action实现感知接口.
    简单/操作麻烦/让Action和Servlet的API耦合在一起了.
  • 2.使用ServletActionContext类.
    理解/使用都很简单/让Action和Servlet的API存在耦合.
  • 3.使用ActionContext类.
    简单/让Action和Servlet的API没有耦合,但是不能操作Cookie.

在开发中,使用方式2和方式3比较多,Struts2官方建议使用方式3.先使用方式3,搞不定再使用方式2.

2.Action获取请求参数三种方式


J2EE的最佳实践:按照功能职责,分层开发:
表现层:
职责:
1.接受请求数据
2.把数据封装Model对象
3.调用业务逻辑方法处理请求
4.控制界面跳转

MVC思想:
M:数据对象.
V:JSP
C:StrutsPrepareAndExecuteFilter(前端控制器.)
问题:Action到底充当什么角色?

Action获取请求参数三种方式:

1).第一种:Action本身作为Model对象,通过setter方法封装(属性注入)

JSP(注意表单参数的名字):

Paste_Image.png

Action:

Struts2(二)_第4张图片
Paste_Image.png

注意:表单中的参数名称要和Action中的setter方法的属性名相同.

2).第二种:创建独立Model对象,页面通过ognl表达式封装(属性注入)

1):创建Model对象,封装参数数据信息.

Struts2(二)_第5张图片
Paste_Image.png

2):JSP(注意表单参数的名字):

Paste_Image.png

给当请求Action中的user属性对应的对象中,设置username和password值.

Action中的:user属性.--->对应一个对象.
user属性对应对象的:username/password属性

:先从Action中获取是否有user对象(getUser方法),
如果有,就直接在该对象中设置其他参数值.
如果没有:创建新的User对象.

User user = Struts2框架通过getUser方法来获取User对象.
if(uesr ==null){
   user = new User();
}
把参数设置到user对象中去.

3):Action代码:

Struts2(二)_第6张图片
Paste_Image.png

方式1:同时提供getter/setter.
方式2:在生命对象的时候,new出来,再提供getter方法即可.

Struts2(二)_第7张图片
Paste_Image.png

3).第三种:使用ModelDriven接口,对请求数据进行封装(模型驱动)

1):JSP(注意表单参数的名字):

Paste_Image.png

username和password对应:
Model中的属性:

2):Action类:

Struts2(二)_第8张图片
Paste_Image.png

4).Action获取请求参数三种方式对比:

第一种:Action本身作为Model对象,通过setter方法封装(属性注入)
1:如果参数比较多,此时Action中将提供大量字段和setter方法,Action很臃肿.
2:我们还得手动把数据封装到对象中去.
第二种:创建独立Model对象,页面通过ognl表达式封装(属性注入)
1:表单参数的name属性值,不是很清晰.
第三种:使用ModelDriven接口,对请求数据进行封装(模型驱动)
1:不能为多个对象封装数据.

一般的,我们在开发中使用第二种较多.
但是,修改密码的操作:
在User对象中,只有密码这个属性.
有时候,我们是方式1+方式2或者方式1+方式3.

3.Interceptor(拦截器)的美


拦截器:Interceptor

拦截器:
Struts2拦截器是在访问某个Action的某个方法之前或之后实施拦截,并且Struts2拦截器是可插拔的,拦截器是AOP的一种实现.

AOP:
面向切面编程.其实现原理:动态代理模式--->留给Spring

WebWork中文文档解释:
拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个Action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也提供了一种可以提取Action中可重用的代码的方式。

拦截器栈(Interceptor Stack):
Struts2拦截器栈就是将拦截器按一定的顺序连接成一条链。在访问被拦截的方法或字段时,Struts2拦截器链中的拦截器就会按其之前定义的顺序被调用。

拦截器的"美":

DRY原则:Dont't Repeat Yourself.

拦截器在设计和程序结构上的优点:
拦截器能把很多功能从Action中独立出来,分散到不同的拦截器里面,减少了Action的代码。如此,拦截器和Action本身的功能都更单一了。当通用的功能代码被封装在拦截器里面(代码模块化),就可以对不同的Action,根据功能需要,来配置相应功能的拦截器了。提高了拦截器所实现的功能的重用性,也变相实现了装配式和可插拔式的体系结构,使得整个系统结构变得更灵活。
1.简化Action的实现
2.功能更单一
3.通用代码模块化
4.提高重用性

4.Struts2执行流程


1).Struts2的执行步骤:

  • ①.客户端发送请求;
  • ②.该请求经过一系列的过滤器(Filter):其中可选过滤器ActionContextCleanUp,帮助Struts2和其他框架集成。例如:SiteMesh Plugin。
  • ③.接着FilterDispatcher被调用,FilterDispatcher询问ActionMapper,来决定该请求是否需要调用某个Action。
  • ④.若ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy。
  • ⑤.ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类。
  • ⑥.ActionProxy创建一个ActionInvocation的实例。
  • ⑦.ActionInvocation实例调用Action的前后,涉及到相关拦截器(Intercepter)的调用。
  • ⑧.一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果是一个JSP或其他页面(也可以是其他的Action链)。 JSP页面展现可使用Struts2框架中的标签(该过程会涉及ActionMapper)。

在上述过程中所有的对象(Action、Interceptors、Results等)都由xwork容器中的ObjectFactory创建。

Struts2(二)_第9张图片
Paste_Image.png
Struts2(二)_第10张图片
Paste_Image.png

2).Struts2中内置的拦截器:

在struts-core-2.3.x.jar--->struts-default.xml中

常见的拦截器:

  • 1:params拦截器
    这个拦截器偷偷的把请求参数设置到相应的Action的属性去的,并自动进行类型转换。
  • 2.modelDriven拦截器
    如果Action实现ModelDriven接口,它将getModel()取得的模型对象存入OgnlValueStack中。
  • 3.execption拦截器
    顾名思义,在抛出异常的时候,这个拦截器起作用。最好把它放在第一位,让它能捕获所有的异常。
  • 4.validation拦截器
    调用验证框架读取 *-validation.xml文件,并且应用在这些文件中声明的校验。
  • 5.token拦截器
    核对当前Action请求(request)的有效标识,防止重复提交Action请求。
  • 6.fileUpload拦截器
    用来处理文件上传
  • 7.workflow拦截器
    调用Action的validate方法,一旦有错误返回,重新定位到INPUT结果视图
  • 8.servletConfig
    通过感知接口,获取感应对象
Struts2(二)_第11张图片
Paste_Image.png

5.自定义拦截器


1).需求:

做一个登陆拦截器(LoginCheckInterceptor),拦截Action访问.
如果强行访问某一个需要登陆之后才能访问的Action,直接跳转到登录页面.

Struts2(二)_第12张图片
Paste_Image.png

2).操作步骤:

步骤1.定义拦截器类

方式1:实现com.opensymphony.xwork2.interceptor.Interceptor接口.

方式2:继承com.opensymphony.xwork2.interceptor.AbstractInterceptor类.

Struts2(二)_第13张图片
Paste_Image.png

步骤2.在struts.xml中注册拦截器

第一步:先在中声明拦截器LoginInterceptor.

第二步:在中来引用LoginInterceptor拦截器.

Struts2(二)_第14张图片
Paste_Image.png

上图的拦截器引用配置:
因为是在中引用了登录拦截器,所以只有当前Action才会做登录拦截功能.其他Action元素,没有这个功能.
如果其他多个action元素都做登录检查功能,那么所有action元素都得配置:

如此一来,重复配置.

3).可以通过全局配置拦截器:

Struts2(二)_第15张图片
Paste_Image.png

如果不拦截某一个Action:
1.方式一:代码中放行:

Struts2(二)_第16张图片
Paste_Image.png

2.方式二:默认拦截器

Struts2(二)_第17张图片
Paste_Image.png

6.OGNL和ValueStack(值栈)


1).什么是OGNL

OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。

Struts2框架使用OGNL作为默认的表达式语言。

EL(表达式语言),OGNL就是EL的升级版.

作用:Action和视图(JSP)之间数据交互的桥梁.

讲解OGNL之前,先得学习ValueStack.

2).什么是ValueStack

值栈是对应每一个请求对象的轻量级的内存数据中心。

每一次请求的时候,都会创建一个新的ValueStack对象,该ValueStack对象封装了这一次请求相关的数据信息.

  • 1).ValueStack实际是一个接口,在Struts2中利用OGNL时,实际上使用的是实现了该接口的OgnlValueStack类,这个类是Struts2利用OGNL的基础。
  • 2).ValueStack贯穿整个Action的生命周期(一次请求):每个Action类的实例都拥有一个ValueStack对象。 ValueStack相当于数据的中转站,在其中保存该次请求和当前Action对象和其他相关对象信息。

每一次的请求: 一个新的Action对象,新的ActionContext对象,新的ValueStack对象.

  • 3).Struts2框架把ValueStack对象保存在名为“struts.valueStack”的request属性中。

3).如何获取ValueStack.

  • 方式1: 因为ValueStack在请求中,属性名为:struts.valueStack.
         ValueStack vs = request.getAttribute("struts.valueStack");
         ValueStack vs = ServletActionContext.getRequest().getAttribute("struts.valueStack");
         ValueStack vs = ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
  • 方式2: 通过ActionContext对象获取
         ValueStack vs = ActionContext.getContext().getValueStack();

以上两种方式获取的是同一个ValueStack对象.

Paste_Image.png

4).ValueStack内部结构

ValueStack对象中有两个很重要的属性,这两个属性就是ValueStack的主要内部结构:

属性 类型 数据储存类型 引用 获取数据
root CompoundRoot extends ArrayList : 栈的数据结构(后进先出) 主要存储Action对象相关的数据信息. - 从root中获取数据: 直接使用属性名获取. --->
context Map 上下文 主要存储映射关系数据.(key-value). 存在用root对象的引用(只要拿到context对象就可以获取到root对象);context中还存在request、session、application、attr、parameters对象的引用。 从context中获取数据: #key --->
Struts2(二)_第18张图片
Paste_Image.png
Struts2(二)_第19张图片
Paste_Image.png
Struts2(二)_第20张图片
Paste_Image.png

5).把数据放入ValueStack.

1.把数据放入root中:(栈,ArrayList.每次都要压在栈顶)

  • 方式1:ValueStack对象.getRoot().add(0, Obejct val);//把数据压入栈顶
  • 方式2:ValueStack对象.getRoot().push(Object val):等价于valueStack对象.getRoot().add(0, Obejct val);
  • 方式3:ValueStack对象.set(String propertyName,Object value);
  • 方式4.在Action中提供一个可访问的属性(getter方法).

此时:Action在栈顶,往Action中存储属性和属性值.

2).把数据放入context中:

  • 方式1:ValueStack对象.getContext().put(String key,Object value); 太长了.
  • 方式2:ActionContext对象.put(String key,Object value);

一般的:把集合中的数据放入context中.

6).如何从JSP中取出ValueStack中的数据:

  • 此时必须使用Struts的标签.--->先引入Struts2标签
<%@ taglib uri="/struts-tags" prefix="s"%>
  • Struts2的调试标签: :主要用来观察数据在哪一个空间(root,context).

  • 访问方式:.
    1).获取root中数据:
    若:放入root中的数据,没有属性名::栈顶是0.
    2).把context中数据:

Struts2(二)_第21张图片
Paste_Image.png

EL可以访问ValueStack中的数据:
不建议这么做,为什么可以呢:
Struts2重新包装而来请求对象.${msg}---><%=pageContext.findAttribute("msg") %>
StrutsRequestWrapper:先从ValueStack中取出数据,再放入request中.

你可能感兴趣的:(Struts2(二))