关闭

深入解析Struts控制器组件

1310人阅读 评论(1) 收藏 举报
 

1.引言
关于Struts项目,在以前的文章中我已经做过一些介绍,在此不再赘述。写本文,旨在从控制器的层面进一不加深对Struts MVC模型的理解和认识.

2.进入主题
Struts控制器组件负责接收用户请求、更新模型,以及选择合适的视图组件返回给用户。控制器组件有助于将模型层和视图层分离,有了之中分离,就可以在同一个模型的基础上得心应手的开发多种类型的视图。
Struts控制器组件主要包括:
ActionServlet组件:充当Struts框架的中央控制器。
RequestProcessor组件:充当每个子应用模块的请求处理器。
Action组件:负责处理一项具体的业务。
Struts框架采用ActionServlet和RequestProcessor组件进行集中控制,并采用Action组件来处理单项业务。之中控制方式就能够满足MVC设计模式的两大需求:
首先,控制器的用户输入数据和模型层之间充当媒介/翻译者的角色,提供一些通用的功能,当系统的这些功能出现需求变更时,不需要修改整个应用,只需要修改
局部的控制器组件即可。
其次,由于所以的请求都经过控制器的过滤,因此可以降低视图组件之间,以及视图组件和模型组件之间的相互依赖关系,提高每个组件的相对独立性。由控制器组件来决定把合适的视图组件返回给用户,这可以减少视图组件之间直接的、错综复杂的链接关系,使得应用更加灵活便于维护。
2.1.控制器组件的控制机制
Struts的控制器组件主要完成以下任务:
接收用户请求。
根据用户请求,调用相应的模型组件来执行相应的业务逻辑。
获取业务逻辑执行结果。
根据当前状态以及业务逻辑执行结果,选择合适的视图组件返回给用户。
在Struts组件中,由如下一系列相关联的组件来共同完成控制任务。
2.1.1.ActionServlet类
org.apache.struts.action.ActionServlet类是Struts框架的核心控制器组件,所有的用户请求都先由ActionServlet来处理,然后在由它把请求转发给其他组件。Struts框架只允许早一个应用中配置一个ActionServlet类,在应用的生命周期中,仅创建ActionServlet类的一个实例,这个AtionServlet实例可以同时响应多个用户请求。
2.1.2.RequestProcessor类
对于多运用模块的Struts应用,每个子应用模块都有各自的RequestProcessor实例.在ActionServlet的process()方法中,一旦选择了正确的子应用模块,就会调用子应用模块RequestProcessor实例的的process()方法来处理请求.在ActionServlet调用这个方法时,会把当前的request和response对象传给它.Struts框架只允许应用中只存在一个ActionServlet实例,但是可以存在多个RequestProcessor类,每个子应用都有单独的RequestProcessor类.
2.1.3.Action类
Action类是用户请求和业务逻辑之间的桥梁.每个Action充当客户的一项业务代理.在RequestProcessor类预处理请求时,在创建了Action的实例后,就调用自身的processActionperform()方法,该方法再调用Action类的execute()方法.Action类的execute()方法再调用模型组件的业务方法,完成用户请求的业务逻辑处理,然后根据执行结果把请求转发给合适的Web组件.
为了确保线程安全,在一个应用的生命周期中,Struts框架只会为每个Action类创建一个实例.所有的客户请求共享一个实例,并且所有请求线程可以同时执行它的execute()方法.
2.1.4.ActionForward类
Action类的execute()方法返回一ActionForwad对象.ActionForward对象代表了Web资源的逻辑抽象.这里的资源可以是JSP页/Java Servlet或Action.从execute()方法中返回ActionForward对象有两种方法:
第一:在execute()方法中,动态创建一个ActionForward实例,
return new ActionForward("Failure","/security/error.jsp","true");
以上ActionForward构造方法的第一个参数代表ActionForward实例的逻辑名,第二个参数指定转发路径,第三个参数指定是否进行重定向.(true:重定向;false:请求转发)
第二:在Struts配置文件中配置<forward>元素.
    <action name="loginActionForm"
            parameter="reqCode"
            path="/login"
            scope="request"
            validate="false"
            type="com.eRedLab.eRedCIP.frame.web.LoginAction">
              <forward name="Failure" path="/security/error.jsp" />
    </action>
配置了<forward>元素后,在Struts框架初始化时就会创建存放<forasrd>元素配置信息的ActionForward对象.在Action的execute方法中只需调用Actionmapping实例的findForward()方法,来获得特定的ActionForward实例:
return mapping.findForward("Failure");
采用第二中方法,无需在程序中硬编码来指定转发资源的物理路径.而是在配置文件中配置转发资源,程序中只需要引用转发资源的逻辑名即可.这有效提高了应用的灵活性和可维护性.

2.2.使用内置的Struts Action类
Struts提供了一些现成的Action类,在Struts应用中直接使用这些Action类可以大大节省开发时间.下面就将介绍几个最常用的Action类:
2.2.1.org.apache.struts.actions.ForwardAction类
在JSP网页中,尽管可以直接通过<jsp:forward>标签把请求转发给其他Web组件,但是Struts框架提倡先把请求转发给控制器,再由控制器来负责请求转发.
由控制器来负责请求转发有一下一些优点:
2.2.1.1.控制器具有预处理请求功能,它能够选择正确的子应用模块来处理请求,并且把子应用模块的MoudleConfig和MessageResources对象存放在Request范围内.这样,请求转发的目标WEB组件就可以正常的访问MoudleConfig和MessageResources对象.
2.2.1.2.如果JSP页面中包含HTML表单,那么控制器能够创建和这个表单对应的ActionForm对象,把用户输入的表单数据组装到ActionForm中.如果<action>节点的validate属性为true,那么还会调用ActionForm的表单验证方法.控制器把ActionForm对象存放在request或session范围内,这样请求转发的目标Web组件也可以访问ActionForm.
2.2.1.3.JSP网页之间直接相互转发违背了MVC的分层原则.按照MVC设计思想,控制器负责处理所有请求,然后选择恰当的视图组件返回给用户.
对于用户自定义的Action类,既可以负责请求转发,还可以充当客户端的业务代理.如果仅仅需要Action类提供请求转发功能,则可以使用ForwarAction类.ForwardAction专门用于请求转发,不执行任何业务操作.
2.2.2.org.apache.struts.actions.DispatchAction类
通常在一个Action中只能完成一种业务操作,如果希望在同一个Action中完成一组相关的业务操作,就要使用DispatchAction类.
创建一个扩展DispatchAction的子类,不必覆盖execute()方法,而是创建一些实现业务操作的方法,这些业务方法都应该和execute()方法具有同样的业务签名,即她们的参数和返回类型都相同.此外,也应该声明抛出Exception.
在配置DispatchAction类时,需要把parameter属性设置为"method":
    <action
        name="testTagNo1ActionForm"
        parameter="method"
        path="/testTagNo1"
        scope="request"
        type="com.eRedLab.eRedCIP.test.web.TestTagNo1Action">
     <forward name="jspView" path="/testTagNo1.jsp" />
    </action>
把parameter的属性设置为"method"后,当用户请求访问DispatchAction时,应该提供method请求参数.例如:
http://localhost:8080/eredcip/testTagNo1.do?method=addItem&id=2
以上method请求参数值为:"addItem",它指定了需要调用的业务方法,因此DispatchAction将调用相应的addItem()方法.
2.2.3.org.apache.struts.actions.LookupDispatchAction类
LookupDispatchAction类是DispatchAction的子类.在LookupDispatchAction中也可以定义多个业务方法.通常LookupDispatchAction主要用于在一个表单中有多个提交按钮,而这些按钮又有一个共同的名字的场合.这些按钮的名字和具体的ActionMapping的parameter属性值对应.下面举例说明如何使用LookupDispatchAction类:
首先,在同一个表单中定义多个提交按钮.如下:Test1.jsp
<html:form action="/processcheckout">
......
<html:submit property="action">
<bean:message key="button.save">
</html:submit>
<html:submit property="action">
<bean:message key="button.checkout">
</html:submit>
</html:form>
以上JSP代码的输出内容为:
<form name="checkoutForm" method="post" action="security/processcheckout.do">
......
<input type="submit" name="action" value="save"/>
<input type="submit" name="action" value="checkout"/>
</form>
接着,创建一个扩展LookupDispatchAction类得子类.
在ProcessCheckoutAction类中实现getKeyMethodMap()方法,这个方法返回包含key/value数据的java.util.Map对象.Map对象中的Key和<bean:message>标签的key属性匹配.value和LookupDispatchAction子类的业务方法名匹配.
以下为ProcessCheckOutAction类的getKeyMethodMap()方法:
protected Map getKeyMethodMap(){
    Map map = new HashMap();
    map.put("button.checkout","checkout");
    map.put("button.save","save");
    return map;
}
根据以上程序,应该在ProcessChecoutAction中提供两个业务方法checkout()和save();当用户提交[checkout]按钮,Shtuts框架就会调用checkout()方法;当用户提交[save]按钮时,就会调用save()方法.这些业务方法都应该和execute()方法有同样的方法签名,即它们的参数和返回类型都应该相同.业务方法声明抛出的异常为:
IOException和ServletException.
最后,在ProcessCheckoutAction的配置文件中,应该把<action>元素的parameter属性值设置为action.使它和<html:submit>标签的property属性保持一致.

3.结束语
本文从控制器的角度深入介绍了构成Struts框架的中央控制器ActionServlet和RequestProcessor的控制流程.一个Struts应用只能有一个ActionServlet实例,对于每和子应用模块都有各自的RequestProcessor实例.在Web应用描述符文件中的ActionServlet初始化阶段负责加载每个子应用模块的Struts配置文件,并把所有的配置信息保存到内存中相关配置类的实例中.

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:280944次
    • 积分:3660
    • 等级:
    • 排名:第9224名
    • 原创:62篇
    • 转载:93篇
    • 译文:0篇
    • 评论:38条
    最新评论