此后,所有以.action 结尾的服务请求将由 ServletDispatcher 接管。
ServletDispatcher 接受到 Servlet Container 传递过来的请求,将进行一下几个动作:
1. 从请求的服务名(/login.action)中解析出对应的 Action 名称(login)
2. 遍历 HttpServletRequest、HttpSession、ServletContext 中的数据,并将其复制到 Webwork 的 Map 实现中,至此之后,所有数据操作均在此 Map 结构中进行,从 而将内部结构与 Servlet API 相分离。
至此,Webwork 的工作阶段结束,数据将传递给 XWork 进行下一步处理。从这里也可以看 到 Webwork 和 xwork 之间的切分点,Webwork 为 xwork 提供了一个面向 Servlet 的协议转换 器,将 Servlet 相关的数据转构转换成 xwork 所需要的通用数据格式,而 xwork 将完成实际的 服务调度和功能实现。
这样一来,以 xwork 为核心,只需替换外围的协议转换组件,即可实现不同技术平台之间的 切换(如将面向 Servlet 的 Webwork 替换为面向 JMS 的协议转换器实现,即可在保留应用逻 辑实现的情况下,实现不同外部技术平台之间的移植)。
3. 以上述信息作为参数,调用 ActionProxyFactory 创建对应的 ActionProxy 实例。
ActionProxyFactory 将 根据 Xwork 配置 文件( xwork.xml) 中的 设定 ,创 建 ActionProxy 实例,ActionProxy 中包含了 Action 的配置信息(包括 Action 名称,
对应实现类等等)。
4. ActionProxy 创建对应的 Action 实例,并根据配置进行一系列的处理程序。包括 执行相应的预处理程序(如通过 Interceptor 将 Map 中的请求数据转换为 Action 所需要的 Java 输入数据对象等),以及对 Action 运行结果进行后处理。
ActionInvocation 是 这 一 过 程 的 调 度 者 。 而 com.opensymphony.xwork.
DefaultActionInvocation 则是 XWork 中对 ActionInvocation 接口的标准实现,如 果有精力可以对此类进行仔细研读,掌握了这里面的玄机,相信 XWork 的引擎 就不再神秘。
下面我们来看配置文件:
xwork.xml:
<!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN"
"http://www.opensymphony.com/xwork/xwork-1.0.dtd">
<xwork>
<include file="webwork-default.xml" /> ⑴
<package name="default" extends="webwork-default"> ⑵
<action name="login" ⑶
class="net.xiaxin.webwork.action.LoginAction">
<result name="success" type="dispatcher"> ⑷
<param name="location">/main.jsp</param>
</result>
<result name="loginfail" type="dispatcher">
<param name="location">/index.jsp</param>
</result>
<interceptor-ref name="params" /> ⑸
<interceptor-ref name="model-driven"/> ⑹
</action>
</package>
</xwork>
⑴
include
通过 include 节点,我们可以将其他配置文件导入到默认配置文件 xwork.xml 中。
从而实现良好的配置划分。
extends="webwork-default"
"webwork-default"是 webwork-default.xml
文件中定义的 package,这里通 过继承,"default" package 自动拥有"webwork-default" package 中的所有 定义关系。这个特性为我们的配置带来了极大便利。在实际开发过程中,我们可以根据自身 的应用特点,定义相应的 package 模板,并在各个项目中加以重用,无需再在重复 繁琐的配置过程中消耗精力和时间。
此外,我们还可以在 Package 节点中指定 namespace,将我们的 action 分为若干个 逻辑区间。如:
<package name="default" namespace="/user"
extends="webwork-default">
就将此 package 中的 action 定义划归为/user 区间,之后在页面调用 action 的时候,
我们需要用/user/login.action 作为 form action 的属性值。其中的/user/就指定了此 action 的 namespace,通过这样的机制,我们可以将系统内的 action 进行逻辑分类,
从而使得各模块之间的划分更加清晰。
⑶
action
Action 配置节点,这里可以设定 Action 的名称和对应实现类。
⑷
result
通过 result 节点,可以定义 Action 返回语义,即根据返回值,决定处理模式以及 响应界面。
这里,返回值"success"(Action 调用返回值为 String 类型)对应的处理模式为
"dispatcher"。
可选的处理模式还有:
⑷
interceptor-ref
设定了施加于此 Action 的拦截器(interceptor)。关于拦截器,请参见稍后的“XWork 拦截器体系”部分。
interceptor-ref
定义的是一个拦截器的应用,具体的拦截器设定,实际上是继承于
webwork-default package,我们可以在 webwork-default.xml
中找到对应的"params"和"model-driven"拦截器设置:
<interceptors>
……
<interceptor name="params"
class="com.opensymphony.xwork.interceptor.ParametersInt erceptor" />
<interceptor name="model-driven"
class="com.opensymphony.xwork.interceptor.ModelDrivenIn terceptor" />
……
</interceptors>
"params"大概是 Webwork 中最重要、也最常用的一个 Interceptor。上面曾经将
MVC 工作流程划分为几个步骤,其中的第一步:“将 Web 页面中的输入元素封装为一个(请求)数据对象”
就是通过"params"拦截器完成。Interceptor 将在 Action 之前被调用,因而,
Interceptor 也成为将 Webwork 传来的 MAP 格式的数据转换为强类型 Java 对象的 最佳实现场所。
"model-driven"则是针对 Action 的 Model 驱动模式的 interceptor 实现。具体描
述请参见稍后的“Action 驱动模式”部分很可能我们的 Action 都需要对这两个 interceptor 进行引用。我们可以定义一个 interceptor-stack,将其作为一个 interceptor 组合在所有 Action 中引用。如,上面 的配置文件可修改为:
<xwork>
<include file="webwork-default.xml" />
<package name="default" extends="webwork-default">
<interceptors>
<interceptor-stack name="modelParamsStack">
<interceptor-ref name="params" />
<interceptor-ref name="model-driven" />
</interceptor-stack>
</interceptors>
<action name="login"
class="net.xiaxin.webwork.action.LoginAction">
<result name="success" type="dispatcher">
<param name="location">/main.jsp</param>
</result>
<result name="loginfail" type="dispatcher">
<param name="location">/index.jsp</param>
</result>
<interceptor-ref name="modelParamsStack" />
</action>
</package>
</xwork>
通过引入 interceptor-stack,我们可以减少 interceptor 的重复申明。
下面是我们的 Model 对象:
LoginInfo.java: