)。ActionServlet委派请求是基于客户端传入的URI。一旦Action类完成处理,ActionServlet根据Action返回的键值来决定在什么视图中显示Action的类处理结果。ActionServlet类似于一个创建Action对象的工厂,由Action对象去执行应用中实际的业务逻辑。控制器是Struts框架中最重要的部分。
1.6.1 Struts的运行过程
下面是一幅和MVC模式对应的STRUTS框架图
视图(view1)
Action1
Action2
ActionServlet Action3
(控制器)
Action4
视图(view2) 模型(Model)
图7 STRUTS框架图
图7是Struts框架下应用程序请求流通过的路径。这个处理过程由5个基本的步骤组成。
下面是处理步骤的描述。
1.由显示视图产生一个请求。
2. 请求被ActionServlet(控制器)接收,它在struts-config.xml文件中寻找请求的URI,找到对应的Action类后,Action类执行相应的业务逻辑。
3. Action类执行建立在模型组件基础上的业务逻辑,模型组件是和应用程序关联的。
4. 一旦Action类处理完业务逻辑,它把控制权返回给ActionServlet。,Action类提供一个键值作为返回的一部分,它指明了处理的结果。ActionServlet使用这个键值来决定在什么视图中显示Action的类处理结果。
5. 当ActionServlet把Action类的处理结果传送到指定的视图中,请求的过程也就完成了。
HttpServlet FrowardConfig
<<front controller>>
org.apache.struts.action.ActionServlet org.apache.struts.action.ActionForWard
<<dispatcher>> ActionConfig
org.apache.struts.action.RequestProcessor org.apache.struts.action.ActionMapping
Serializable
<<view helper>> <<request handler>>
org.apache.struts.action.ActionForm org.apache.struts.action.Action
图8 Struts中MVC实现
图8中各个类的语义
1. ActionServlet类:实现控制器,Struts必需的配置在ActionServlet.init()方法中加载。ActionServlet将所有的输入请求委托给RequestProcessor.
2. RequestProcessor类:分配器,所有输入的请求都被控制器委托给分配器(dispatcher).
3. ActionForm类:存储表单数据,由ActionForm派生出来的对象用于存储请求对象中的参数,因此它们和用户是紧密耦合的。
4. ActionForward类:ActionForward对象是配置对象。这些配置对象有唯一的标识符,以使它们根据有意义的名称进行寻找。ActionForward对象封装提交的URL路径,它被请求处理程序用来标识目标视图。
5. ActionMapping类:它提供了引入的请求和相应的请求处理程序之间的映射。
6.Action类:请求处理程序。Action类的子类作为适配器用于引入的请求和模型之间。Action类的子类是为每个请求单独创建的。Action的基类提供了访问与框架相关的资源的公共函数,以及保存由它的子类的exectue(…)方法进行检查而得到错误的方法。
1.6.2 Struts的主要组件:
1.6.2.1 控制器对象
控制器语义有ActionServlet。控制器语义提供了处理所有客户请求的中心位置。这就为控制器层提供了一个清楚的工作分配情况,控制器层主要的工作是处理试图和导航管理、将模型访问和操作交给有特定请求的请求处理程序(Command对象[Gof])。所有引入的请求被映射到部署描述符的中心控制器上。
1.6.2.2 分配器对象
RequestProcessor作为一个分配器运行,并通过实例化(或重用)一个请求处理和对应的表单bean来处理客户机请求。创建的错误或是表单bean和请求处理程序抛出的异常(由RequestProcessor处理),影响了RequestProcessor的视图管理功能。表单bean帮助RequestProcessor存储表单数据和分段传输视图需要的中间模型数据,RequestProcessor使用<action>声明实例化特定请求的请求处理程序。
1.6.2.3请求处理程序
Action类的子类作为适配器用于引入的请求和模型之间。请求最初由RequestProcessor截获,RequestProcessor则实例化一个对应的请求处理程序。这个从Action类继承而来的对象(也称为请求处理程序)是为每个请求而特别创建的。客户机请求封装请求URI中所需的动作作为servlet路径,该路径信息随后有分配器(RequestProcessor)提取,从而创建相应的请求处理程序来处理程序实例。命令模式将URI从请求处理程序中分离出来。
1.6.3 Struts的配置文件struts-config.xml
Struts 的核心是控制器ActionServlet,而ActionServlet的核心是配置文件struts-config.xml,该配置文件的主要作用是建立控制器与模型之间的联系。它描述了控制器将客户请求映射到对应处理的法则,同时还定义了用户输入数据与ActionFor。组件的对应映射关系。此外,该配置文件的另一个作用是将逻辑名映射到物理路径,使得物理路径与程序路径无关,整个系统导航使用逻辑名在struts-config.xml中完成。
这种在配 置文件中完成业务逻辑控制的方法主要有以下几个优点:首先,应用的所有页面的导航定义都集中在一个分等级的文本文件中,通过此配置文件即可迅速把握整个系统的脉络;第二,网页设计人员在修改网页时无需遍历Java代码来理解应用的业务逻辑,而当业务逻辑发生改变时,业务逻辑开发者也只需在struts-config.xml中做出相应的调整和修改,而无需重新编译代码。在大型的Web应用系统中,这种管理页面逻辑的方式无论是在系统前期的开发过程,还是后期的维护与升级阶段都显示出了方便性和有效性。
struts-config.xml的正文部份由八个元素组成,下面将对系统中涉及的元素的功能与使用方法举例阐明。
1.6.3.1 定义ActionForm
ActionServlet使用ActionForm来保存请求参数,这些Bean的属性名称与HTTP请求参数中的名称相对应,控制器将请求参数传递到ActionFormBean的实例中,然后将这个实例传送到Action类。Struts的配置文件struts-config.xml提供了一个<form-beans>元素用于统一管理系统中所有的ActionForm Bean。每个ActionForm Bean都由一个相应的<form-bean>元素创建。在运行时,控制器通过调用适当的ActionForm Bean来确定被创建的ActionForm对象及特性。下面是项目中一个针对常规ActionForm的<form-bean>元素配置:
<form-beans>
<form-bean name="userInfoForm" type="aiai.keyan.manage.user_Manage.pursuerInfoBean" />
</form-beans>
其中,属性name是表单bean在相关作用域的名称,它用于将ActionFormBean与ActionMapping进行关联;而属性type是类的完全限定名。
1.6.3.2 定义全局转发
在常见的Web应用中,多数URI都与应用中的物理文件直接映射,这在应用开发的初级阶段显得较为容易。但是,在应用开发的后期或维护阶段,应用的逻辑通常会发生改变,这时就必须更新整个应用,如果遗漏了某部分,就会产生“异常更新”。这一点给应用的后期开发者和维护人员造成了不小的困难。为了解决这一难题,在Struts应用中,开发人员将逻辑名映射到物理地址,在应用中使用逻辑名实现系统导航,这就使得应用的物理地址与程序地址无关。而元素<global-forwards>就是用于实现这个功能。这个元素可以包含任意个<forward/>子元素,每一个子元素对应一个逻辑名与一个物理地址的映射。当系统的逻辑发生改变时,开发人员只需修改相应<forward/>中的映射关系即可。如下所示:
<global-forwards>
<forward name="forStep1"
path="/researching/datainput/step1.jsp" />
</global-forwards>
上述代码是项目的配置文件中的一部分。其中,属性name表示全局转发的逻辑名,path表示目标URI的物理路径。除了可 以 在<global-forwards>元素中部署全局转发外,开发人员除还可以在<action>元素中部署局部转发, 局部转发仅针对对应的ActionMapping有效。
1.6.3.3 定义Action映射
<Action -Mapping>元素的作用在于帮助开发人员进行框架内部的流程控制。该元素可以包含任意个<action />子元素。每一个子元素将一个请求URI路径映射到对应的Action类,并且将Action类与对应ActionForm bean相关联。ActionServlet在内部使用这些映射,并将控制转移到特定的Action类实例。所有Action类使用perform()方法实现特定的业务逻辑,然后返回一个ActionForward对象,其中包括响应转发的目标资源名称。下列代码截取自项目的配置文件:
<action-mappings>
<action name="userInfoForm" type="aiai.keyan.manage.user_Manage.Struts.userInfoAction" validate="true"
input="/menage/user/register1.jsp"
scope="request" path="/register1" />
</action-mappings>
其中子元素<action>的属性path表示Action类的相对路径,name表示与指定操作关联的Action Bean的名称,type表示连接到本映射的Action类的全称,scope表示与指定Action对应的ActionForm Bean的作用域,input表示输入表单的路径和发生输入错误时系统应返回的页面。在<action-mappings>元素中还可以使用<forward>子元素定义资源的逻辑名称,该资源是Action类的响应要转发的目标。其中<forward>的属性name表示Action类访问ActionForward时所用的逻辑名,path表示响应转发的目标资源的路径。
1.6.4 Struts的自定义标记库
Struts 提供了一组可扩展的自定义标记库(Taglib),采用这些标记库,可以帮助开发人员简化创建用户界面的过程。目前 Struts提供了四种基本自定义Taglib以及两种附加Taglib .
struts-bean taglib:不仅包含可以在访问bean和bean属性时使用的标记,还包含一些用于消息显示的标记。
struts-html taglib:不仅包含用于创建Struts输入表单的标记,而且包含其它通常用来创建动态HTML用户界面或表格的标记。
struts-logic taglib:该库所包含的标记通常用于管理输出文本的条件生成、循环使用对象集合以重复生成输出文本以及应用程序流管理。
struts-template taglib:该库包含的标记可用作创建动态JSP模板,所有采用同一模板的JSP页面都拥有一个公共的外观或共同的格式。
T iles 插件:除了替代Template的基本模板功能外,还增加了布局定义、虚拟页面定义和动态页面生成等功能。Tiles强大的模板功能能够使页面获得最大的重用性和灵活性,此外,结合Tiles配置文件中的页面定义和Action的转发逻辑(即将一个Action转发到一个在Tile:配置文件中定义的虚拟页面),可以减少页面的数量,从而简化JSP开发。
Nested:该标记库的作用在于让上述的基本Struts自定义标记库的功能能够嵌套应用于上下文,发挥更大的作用。
2.7 WEB服务器的搭建与集成
2.7.1 jsp,Serlvet容器Tomcat
Tomcat是一个免费的开源的Serlvet容器,它是Apache基金会的Jakarta项目中的一个核心项目,由Apache,Sun和其它一些公司及个人共同开发而成。由于有了Sun的参与和支持,最新的Servlet和Jsp规范总能在Tomcat中得到体现。
由于Java的跨平台特性,基于Java的Tomcat也具有跨平台性。与传统的桌面应用程序不同,Tomcat中的应用程序是一个WAR(Web Archive)文件。WAR是Sun提出的一种Web应用程序格式,与JAR类似,也是许多文件的一个压缩包。这个包中的文件按一定目录结构来组织:通常其根目录下包含有Html和Jsp文件或者包含这两种文件的目录,另外还会有一个WEB-INF目录,这个目录很重要。通常在WEB-INF目录下有一个web.xml文件和一个classes目录,web.xml是这个应用的配置文件,而classes目录下则包含编译好的Servlet类和Jsp或Servlet所依赖的其它类(如JavaBean)。通常这些所依赖的类也可以打包成JAR放到WEB-INF下的lib目录下,当然也可以放到系统的CLASSPATH中,但那样移植和管理起来不方便。
在Tomcat中,应用程序的部署很简单,你只需WAR放到Tomcat的webapp目录下,Tomcat会自动检测到这个文件,并将其解压。在浏览器中访问这个应用的Jsp时,通常第一次会很慢,因为Tomcat要将Jsp转化为Servlet文件,然后编译。编译以后,访问将会很快。另外Tomcat也提供了一个应用:manager,访问这个应用需要用户名和密码,用户名和密码存储在一个xml文件中。通过这个应用,辅助于Ftp,你可以在远程通过Web部署和撤销应用。当然本地也可以。 Tomcat不仅仅是一个Servlet容器,它也具有传统的Web服务器的功能:处理Html页面。但是与Apache相比,它的处理静态Html的能力就不如Apache。我们可以将Tomcat和Apache集成到一块,让Apache处理静态Html,而Tomcat处理Jsp和Servlet。这种集成只需要修改一下Apache和Tomcat的配置文件即可。
另外,Tomcat提供Realm支持。Realm类似于Unix里面的group。在Unix中,一个group对应着系统的一定资源,某个group不能访问不属于它的资源。Tomcat用Realm来对不同的应用(类似系统资源)赋给不同的用户(类似group)。没有权限的用户则不能访问这个应用。Tomcat提供三种Realm,1:JDBCRealm,这个Realm将用户信息存在数据库里,通过JDBC获得用户信息来进行验证。2:JNDIRealm,用户信息存在基于LDAP的服务器里,通过JNDI获取用户信息。3:MemoryRealm,用户信息存在一个xml文件里面,上面讲的manager应用验证用户时即使用此种Realm。通过Realm我们可以方便地对访问某个应用的客户进行验证。
在Tomcat中,可以利用Servlet2.3提供的事件监听器功能,来对Application或者Session实行监听。Tomcat也提供其它的一些特征,如与SSL集成到一块,实现安全传输。还有Tomcat也提供JNDI支持,这与那些J2EE应用服务器提供的是一致的。说到这里要介绍一下通常所说的应用服务器(如WebLogic)与Tomcat有何区别。应用服务器提供更多的J2EE特征,如EJB,JMS,JAAS等,同时也支持Jsp和Servlet。而Tomcat则功能没有那么强大,它不提供EJB等支持。但如果与JBoss(一个开源的应用服务器)集成到一块,则可以实现J2EE的全部功能。既然应用服务器具有Tomcat的功能,那么Tomcat有没有存在的必要呢?事实上,在很多中小应用不需要采用EJB等技术,Jsp和Servlet已经足够,这时如果用应用服务器就有些浪费了。而Tomcat短小精悍,配置方便,能满足我们的需求,这种情况下我们自然会选择Tomcat。
Tomcat也可以与其它一些软件集成起来实现更多的功能。如与上面提到的JBoss集成起来开发EJB,与Cocoon(Apache的另外一个项目)集成起来开发基于Xml的应用,与OpenJMS 集成起来开发JMS应用,除了我们提到的这几种,可以与Tomcat集成的软件还有很多。
配置Tomcat虚拟目录,为了使得Tomcat即可以实时对开发工具的修改进行监测,以达到与开发工具实时同步数据。可以在不重启服务器的情况下对项目进行修改。这是非常重要的由于在一台服务器上可能运行这不止一个的WEB项目,在新加项目时不可能让服务器重启,因此必须配置虚拟目录。在{TOMCAT_HOME}/conf/server.xml中的<Host></Host>之间加上
<Context path="dir1"
docBase="D:\web"
reloadable="true" crossContext="true" >
</Context >
其中:
path: web应用的context路径。catalina将每个URL的起始和context path进行比较,选择合适的web应用处理该请求。特定Host下的context path必须是惟一的。如果context path为空字符串(""),这个context是所属Host的缺省web应用,用来处理不能匹配任何context path的请求。
DocBase:该web应用的文档基准目录(Document Base,也称为Context Root),或者是WAR文件的路径。可以使用绝对路径,也可以使用相对于context所属的Host的appBase路径。
Reloadable: 如果希望Catalina监视/WEB-INF/classes/和/WEB-INF/lib下面的类是否发生变化,在发生变化的时候自动重载web application,设为true。这个特征在开发阶段很有用,但也大大增加了服务器的开销。因此,在发布以后,不推荐使用。但是,你可以使用Manager应用在必要的时候触发应用的重载。
CrossContext:如果想在应用内调用ServletContext.getContext()来返回在该虚拟主机上运行的其他web application的request dispatcher,设为true。在安全性很重要的环境中,设为false,使得getContext()总是返回null。缺省值为false。
2.7.2 HTTP服务器Apache2.0
Apache HTTP服务器被设计为一个强大、灵活的能够在多种平台上及不同的环境下工作的服务器。不同的平台和不同的环境经常产生不同的需求,或是会为了达到同样的最佳效果而采用不同的方法。Apache凭借它的模块设计很好的适应了大量不同的环境。这一设计使得网站管理员能够在编译时和运行时凭借载入不同的模块来决定服务器的不同附加功能。
Apache可以在混合多进程、多线程模式下运行,使很多(但不是全部的)配置的可扩缩性得到改善。Apache2.0重写了原来的编译系统,现在是基于autoconf和libtool的,使得Apache的配置系统与其他软件包更加相似。Apache 2.0在诸如BeOS,OS/2和Windows等非Unix平台上有了更好的速度和稳定性。 随着平台特定的multi-processing modules(MPMs)和 Apache Portable Runtime (APR)的引入,Apache在这些平台上的指令由它们本地的API指令实现。 避免了以往使用POSIX模拟层造成的bug和性能低下。
2.7.3 Tomcat与Apache的整合
整合Apache有两个目的
1. 把静态和动态的内容分别有两个不同的服务器承担
2.达到简单的负载均衡
修改Uri mapping的内容即可实现分流
如:
# Uri mapping
[uri:/*.*]
改成
# Uri mapping
[uri:/*.do]
[uri:/*.jsp]
第一步 把mod_jk_2.0.47.dll拷贝到{Apache}\modules文件夹中。
第二步 在{TOMCAT_HOME}\conf中新建一个workers.properties文件内容如下
#####--begin--########
workers.tomcat_home={TOMCAT_HOME} #让mod_jk模块知道Tomcat
workers.java_home={JAVA_HOME} #让mod_jk模块知道j2sdk
ps=\
worker.list=ajp13 #模块版本
worker.ajp13.port=8009 #工作端口
worker.ajp13.host=localhost #主机名称
worker.ajp13.type=ajp13 #类型
worker.ajp13.lbfactor=1 #代理数
######---end---#######
第三步 打开{Apache}\conf\httpd.conf 在文件末尾添加如下内容
########-beging--########
<VirtualHost localhost>
ServerAdmin hua@mzh.com #apache注册的信息
DocumentRoot D:\Web
#与tomcat虚拟目录中docBase相同
ServerName localhost #主机名称
ErrorLog logs/robornet_home_log.txt #日志
CustomLog logs/robornet_Custom_log.txt common
JkMount /* ajp13 #目录中的以下文件由tomcat处理
JkMount /*.jsp ajp13
JkMount /*.do ajp13
JkMount /*.gif ajp13
JkMount /*.jpg ajp13
JkMount /*.css ajp13
JkMount /*.js ajp13
</VirtualHost>
########-end--########
########-beging--########
LoadModule jk_module modules/mod_jk_2.0.47.dll
#装载模块,用于处理连接(对上一行的注释,下同)
JkWorkersFile "{ TOMCAT_HOME }/conf/workers.properties"
#设置模块的工作文件
JkLogFile "{ TOMCAT_HOME }/logs/mod_jk2.log"
#设置模块工作的日志文件,Tocmat启动时会自建
JkLogLevel info
######---end---###########
其中:TOMCAT_HOME是tomcat的路径
JAVA_HOME是j2sdk的路径
Apache是Apache路径