| |
struts控制器组件负责接受用户请求、更新模型,以及选择合适的视图组件返回给用户。控制器组件有助于将模型层和视图层分离,有了这种分离,就可以在同一个模型的基础上得心应手地开发多种类型的视图。struts控制器组建主要包括: ?actionservlet组件:充当struts框架的中央控制器。 ?requestprocessor组件:充当每个子应用模块的请求处理器。 ?action组件:负责处理一项具体的业务。 struts框架采用控制器组件来预处理所有的客户请求,这种集中控制方式可以满足mvc设计模式的两大需求: ?首先,控制器在用户输入数据和模型之间充当媒介 / 翻译者的角色,提供一些通用功能,如安全、登入和其他针对具体用户请求的重要服务,当系统的这些通用功能出现需求变更时,部需要修改整个应用,只需要修改局部的控制器组件即可。 ?其次,由于所有的请求都经过控制器过滤,因此可以降低视图组件之间,以及视图组件和模型组件之间的相互依赖关系,提高每个组件的相对独立性。由控制器组件来决定把合适的视图组件返回给用用户,这可以减少视图组件之间直接的,错综复杂的连接关系,使应用更加灵活,便于维护。 struts框架采用actionservlet和requestprocessor组件进行集中控制,并采用action组件来处理单项业务。 一 控制器组件的控制机制 struts的控制器组件主要完成以下任务: ?接受用户请求 ?根据用户请求,调用合适的模型组件来执行相应的业务逻辑。 ?获取业务逻辑执行结果。 ?根据当前状态以及业务逻辑执行结果,选择合适的视图组件返回给用户。 1 action类 org.apache.struts.action.actionservlet类是struts框架的核心控制器组件,所有的用户请求都先有actionservlet来处理,然后再由actionservlet把请求转发给其他组件。struts框架只允许在一个应用中配置一个actionservlet类,在应用的生命周期中,仅创建actionservlet类的一个实例,这个actionservlet实例可以同时响应多个用户请求。 (a) struts框架初始化过程 (1) 调用initinternal()方法,初始化struts框架内在的消息资源,如与系统日志相关的同志、警告和错误消息。 (2) 调用initother()方法,从web.xml文件中加载actionservlet的初始化参数,如config参数。 (3) 调用initservlet()方法,从web.xml文件中加载actionservlet的url映射信息。此外还会注册web.xml和struts配置文件所使用的dtd文件,这些dtd文件用来验证web.xml和struts配置文件的语法。 (4) 调用initmoduleconfig()方法,加载并解析子应用模块的struts配置文件;创建moduleconfig对象,把它存储在servletcontext中。 (5) 调用initmodulemessageresources()方法,加载并初始化默认子应用模块的消息资源:创建messageresources对象,把它存储在servletcontext中。 (6) 调用initmoduledatasources()方法,加载并初始化默认子应用模块的数据源。如果在struts配置文件中没有定义元素,就忽略这一流程。 (7) 调用initmoduleplugins()方法,加载并初始化默认子应用模块的所有插件。 (8) 当默认子应用模块被成功地初始化后,如果还包括其他子应用模块,将重复流程(4)~(7),分别对其他子应用模块进行初始化。 (b) actionservlet的process()方法 当actionservlet实例接受到http请求之后,在doget()或dopost()方法都会调用process()方法来处理请求。一下是actionservlet的process()方法的源代码: protected void process (httpservletrequest request, httpservletresponse response) throw ioexception, servletexception { moduleutils.getinstance().selectmodule(request, getservletcontext()); getrequestprocessor(getmoduleconfig(request)).process(request, response); } 在process()方法中,首先调用org.apache.struts.util.moduleutils类的selectmodule()方法,这个方法选择负责处理当前请求的子应用模块,然后把与子应用模块相关的moduleconfig和messageresources对象存储倒request范围中,这使得框架的其余组件可以方便地从request范围中读取这些对象,从而获取应用配置信息和消息资源。 process()方法的第二步操作为获得requestprocessor类的实例,然后调用requestprocessor类的process()方法,来完成十几的预处理请求操作。 (c) 扩展actionservlet类 在sturts 1.1 之前的版本中,actionservlet类本身包含了很多处理请求的代码。从struts 1.1 开始,多数功能被移到 org.apache.struts.action.requestprocessor 类中,以便减轻actionservlet类的控制负担。 尽管新版本的struts框架允许在应用中创建矿展actionservlet类的子类,但是这在多数情况下没有必要,因为控制器的多数控制功能位于requestprocessor类中。 如果实际应用确实需要创建自己的actionservlet类,则可以创建一个actionservlet的子类,然后在web.xml文件中配置这个客户化actionservlet类。 如果覆盖了init()方法,应该确保首先调用super.init(),它保证actionservlet的默认初始化操作被执行。除了覆盖init()方法外,事实上,还可以根据十几需要覆盖actionservlet的任何其他方法。 2 requestprocessor类 对于多应用模块的struts应用,每个子应用模块都有各自的requestprocessor实例。在actionservlet的process()方法中,一旦选择了正确的子应用模块,就会调用子应用模块的requestprocessor实例的process()方法来处理请求。在actionservlet调用这个方法时,会把当前的request和response对象传给它。 struts框架只允许应用中存在一个actionservlet类,但是可以存在多个客户化的requestprocessor类,每个子应用模块都可以拥有单独的requestprocessor类。如果想修改requestprocessor类的一些默认功能,可以覆盖requestprocessor基类中的相关方法。 (a) requestprocessor类的process()方法 requestprocessor类的process()方法负责实际的预处理请求操作。 requestprocessor类的process()方法一次执行一下流程: (1) 调用processmultipart()方法。如果http请求方式为post,并且请求的contenttype属性以“multipart/form-data”开头,标准的httpservletrequest对象将被重新包装,以方便处理“multipart”类型的http请求。如果请求方式为get,或者contenttype属性不是“multipart”,就直接返回原始的httpservletrequest对象。 (2) 调用processpath()方法,获得请求uri的路径,这一信息可用于选择合适的struts action组件。 (3) 调用processlocale()方法,当controllerconfig对象的locale属性为true,将读取用户请求中包含的locale信息,然后把locale实例保存在session范围内。 (4) 调用processcontent()方法,读取controllerconfig对象的contenttype属性,然后调用response.setcontenttype(contenttype)方法,设置响应结果的文档类型和字符编码。 (5) 调用processnocache()方法,读取controllerconfig对象的nocache属性,如果nocache属性为true,在响应结果中将加入特定的头参数:pragma、cache-control和expires,防止页面被存储在客户浏览器的缓存中。 (6) 调用processpreprocess()方法。该方法不执行任何操作,直接返回true。子类可以覆盖这个方法,执行客户化的预处理请求操作。 (7) 调用processmapping()方法,寻找和用户请求的uri匹配的actionmapping。如果不存在这样的actionmapping,则向用户返回恰当的错误消息。 (8) 调用processroles()方法,先判断是否为action配置了安全角色,如果配置了安全角色,就调用isuserrole()方法判断当前用户是否具备必需的角色;如果不具备,就结束请求处理流程,向用户返回恰当的错误消息。 (9) 调用processactionform()方法,先判断是否为actionmapping配置了actionform,如果配置了actionform,就先从actionform的存在范围内寻找该actionform实例;如果不存在,就创建一个实例。接下来把它保存在合适的范围中,保存时使用的属性key为actionmapping的name属性。 (10) 调用processactionform()方法。如果为actionmapping配置了actionform,就先调用actionform的reset()方法,再把请求中的表单数据组装到actionform中。 (11) 调用processvalidate()方法,如果为actionmapping配置了actionform,并且actionmapping的validate属性为true,就调用actionform的validate()方法。如果validate()方法返回的actionerrors对象中包
|
|