目前见到的最傻瓜全面的STRUTS入门教程^_^ 一 Jakarta Struts学习之新手上路 Web 应用开发早期曾经是那么的“简单”,那个时候还只是纯HTML页面和浏览器特效而已。因为还涉及不到动态数据操做和商业应用,也就省去了不少麻烦。可是这 样的“简单”只是过眼云烟,现在咱们不得不为复杂的基于Web的商业应用开发采用诸多技术。 本文将介绍如何利用Struts进行应用开发的前台整合的开发过程。Struts是一个为开发基于模型(Model)-视图(View)-控制器 (Controller)(MVC)模式的应用架构的开源框架,是利用Java Servlet和JSP构建Web应用的一项很是有用的技术。 阅 读本文须要读者具备如下几方面的开发经验:JSP、Servlet、自定义标签库(custom tag library)和XML。若是读者想补一补自定义标签库的知识,能够参考做者之前关于这方面的文章。而本文也是关于介绍如何使用Struts系列文章的 上半部分,本系列暂定分为上下两部分。 新手上路注意事项 Struts是一个基于Sun J2EE平台的MVC框架,主要是采用Servlet和JSP技术来实现的。其最初萌芽于Craig McClanahan的构思,诞生至今也一年有余了(译注2)。如今,Struts是Apache软件基金会旗下Jakarta项目组的一部分,其官方网 站是[url]http://jakarta.apache.org/struts[/url]。因为Struts能充分知足应用开发的需求,简单易用, 敏捷迅速,在过去的一年中颇受关注。Struts把Servlet、JSP、自定义标签和信息资源(message resources)整合到一个统一的框架中,开发人员利用其进行开发时不用再本身编码实现全套MVC模式,极大的节省了时间,因此说Struts是一个 很是不错的应用框架。 目前的Struts 1.0修正版包括完整的文档,既能够说是用户文档又是开发指导文档。若是读者是JSP新手,或者对MVC设计模式不是太熟的话,可能刚上路时会比较慢,不过不用担忧,要相信本身会尽快遇上的:) 此 外,应该注意到尽管当前Struts只是1.0版,但已经至关稳定了,做者从Struts 0.9版就在一个大规模的项目中应用了(最近升级到1.0版),至今尚未遇到什么麻烦问题。实际上,Struts在这个要开发复杂用户界面的项目中,为 咱们团队大大的缩短了开发时间,在此衷心的感谢Struts项目团队的全部开发人员。 哦,还有,若是读者开始上路了,要知道Struts的邮件列表但是有至关份量的,在这里混混才可保证能及时跟上Jakarta项目的最新动态哦 [url]http://jakarta.apache.org/site/mail.html[/url]。 开始上路! Struts 框架可分为如下四个主要部分,其中三个就和MVC模式紧密相关: 一、模型(Model),本质上来讲在Struts中Model是一个Action类(这个会在后面详细讨论),开发者经过其实现商业逻辑,同时用户请求 经过控制器(Controller)向Action的转发过程是基于由struts-config.xml文件描述的配置信息的。 二、视图(View),View是由与控制器Servlet配合工做的一整套JSP定制标签库构成,利用她们咱们能够快速创建应用系统的界面。 三、控制器(Controller),本质上是一个Servlet,将客户端请求转发到相应的Action类。 四、一堆用来作XML文件解析的工具包,Struts是用XML来描述如何自动产生一些JavaBean的属性的,此外Struts还利用XML来描述在国际化应用中的用户提示信息的(这样一来就实现了应用系统的多语言支持)。 好,下一步我们来看看构成这个框架的各个部分以及相互之间是怎样运做的吧! 搞定配置 在 使用Struts以前,我们必先设置好JSP服务器,以便让服务器在用户请求时,知道该如何将指定后缀的请求转到相应的 Controller-Struts ActionServlet处理,固然,这些配置信息都通常在服务器启动时经过web.xml文件读入的。咱们能够在web.xml定义多个 Controlloer,为每个应用定义一个。一个典型的web.xml文件配置以下,其中有相应的注释,很好懂的,在后面讨论Action的时候,我 们将主要分析strutc-config.xml。 <web-app> <servlet> <!-- 以 下配置信息声明了Struts中的ActionServlet,即一个名为OreillyAction的Servlet,其具体实现为 org.apache.struts.action.ActionServlet。在这个配置中还有这个Servlet的两个参数:debug level和detail,此处这两个参数的值都设为了2,此外还设置了在启动载入时建立两个实例。 --> <servlet-name>OreillyActionServlet</servlet-name> <servlet-class>org.apache.struts.action.ActionServlet</servlet-class> <init-param> <param-name>config</param-name> <param-value>/WEB-INF/struts-config.xml</param-value> </init-param> <init-param> <param-name>debug</param-name> <param-value>2</param-value> </init-param> <init-param> <param-name>detail</param-name> <param-value>2</param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet> <!-- 设置全部后缀为.action的请求,都转发到OreillyActionServlet --> <servlet-mapping> <servlet-name> OreillyActionServlet </servlet-name> <url-pattern>*.action</url-pattern> </servlet-mapping> <!-- 将初始请求页面设置为login.jsp --> <welcome-file-list><welcome-file>login.jsp</welcome-file></welcome-file-list> <!-- 设置Struts的JSP页面要用到的标签库和她们的路径 --> <taglib> <taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri> <taglib-location>/WEB-INF/struts-bean.tld</taglib-location> </taglib> <taglib> <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri> <taglib-location>/WEB-INF/struts-html.tld</taglib-location> </taglib> <taglib> <taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri> <taglib-location>/WEB-INF/struts-logic.tld</taglib-location> </taglib> </web-app> 控制器(Controller) Controller是这个框架中扮演“交通警察”的角色,当客户端与服务器有交互动做时,都由她来控制。Controller将HTTP请求封包并转发到框架中相应的对象,这些对象多是一个JSP页面或一个Action。 Controller 在web.xml中设置为org.apache.struts.action.ActionServlet的一个实例,在本例中,这个实例就是 OreillyActionServlet。在一个完整的控制过程当中,也就是处理一个HTTP请求时,在控制过程之初,这个Servlet会从一个配置文 件struts-config.xml中获取请求与控制动做向对应的配置信息,这个咱们会在后面详细讨论,Controller经过这些配置信息来决定 HTTP请求该往何处转发,而这些Action在接收到转发来的请求后,实现真正的商业逻辑。咱们要注意的很是重要的一点是Action对象要可以调用这 个ActionServlet的若干方法,经过这个有力的特性,当Action对象在控制过程当中将请求再向别的Action对象转发时(最初的请求是由 ActionServlet获取,向Action对象转发,而Action对象还能够再转发到别的对象),咱们能够将一些须要共享的数据对象经过调用一些 方法放入这个Servlet相关的一些标准容器中捎带过去。 模型(Model) 所谓Model就是在对用户请求的整 个控制过程当中,真正处理用户请求并保存处理结果的对象,在整个过程当中,咱们通常利用JavaBean来把一些信息保存起来以便在各个对象之间传递。由于在 框架中,Model对象是真正处理商业逻辑功能的对象,所以也就是框架中应用需求实现相关性最大的部分。在Struts的实现里,Model的具体表现形 式就是ActionForm对象和与其对应的Action对象了。对用户提交表单的数据进行校验,甚至对数据进行预处理都能在ActionForm中完 成。一般的应用中,通常是一个Model对象和一个请求页面对应的关系,但也能够一个Model对象对应多个页面请求。若是struts- config.xml配置文件没有指定一个Model对象对应的Action,那么控制器将直接把(经过Model对象完成数据封装的)请求转到一个 View对象。 struts-config.xml 前面屡次提到的struts-config.xml配置文件是整 个框架的主心骨。web.xml文件定义了一个请求到来应向何处转发后,后面的工做就全权由struts-config.xml管理控制了。能够说 struts-config.xml就是整个Struts框架的“扛把子”,只有这位“老大”清楚全部请求与动做的映射关系,要是他那里没有搞定或不爽的 话,整个“社团”就什么也摆不平了:)现在的应用系统,XML形式的配置文件愈来愈多,若是整个系统只使用一个这样的配置文件的话,那么保持整个系统的模 块化和可维护性都很是的轻松。使用配置文件来描述请求-动做的控制过程和相互关系,而不是在代码中将对象之间的调用关系写死,那么都应用系统有变更时,我 们只用修改配置文件就好了,而不是再从新编译发布程序了。 Controller经过struts-config.xml文件的配置信息 肯定当有请求时应该调用那个对象来处理,从效率的角度出发,这些信息都是在系统启动时读入并存在内存中的。下面咱们将讲解一个极短小的struts- config.xml文件,文件中定义了一个与登陆请求对应的登陆动做,请求到达后将被转发到 com.oreilly.ui.authentication.actions.LoginAction这个Action对象,该对象处理的结果决定向用 户返回的页面。这个例子同时还示范了一个Action对象将请求转发到别的Action对象,而例子中另外一个返回的对象则是一个View对象,即咱们看到 的login.jsp页面。 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.0//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd";> <struts-config> <!-- ========== Action 映射定义 =================== --> <action-mappings> <!-- <action> 属性的说明 --> <!- type - 完整的Action实现类名 name - 该Action要用到的ActionForm名 path - 请求该Action的URI unknown – 若是将该属性设置为true,那么就是声明这个Action将处理整个应用中全部未找到相应处理Action的请求,固然,一个应用系统中也只会有一个Action的unknown属性能够设为true了 validate - 若是本属性为true则在Action动做以前其对应的ActionForm的validate方法会自动被调用,通常用以校验用户输入的数据 --> <!-- ~~~~~~~~~~~~~~~~~~~~~ --> <!-- O‘Reilly Main Actions --> <!-- ~~~~~~~~~~~~~~~~~~~~~ --> <action path="/Login" type="com.oreilly.ui.authentication.actions.LoginAction"> <forward name="success" path="/DisplayMainPage.action"/> <forward name="failure" path="/login.jsp"/> </action> </action-mappings> </struts-config> 视图(View) View 对象一般来讲都是指的JSP页面。Struts框架实际上并无真正的JSP的要求规范,而是提供了大量的标签库来为开发者更简便的将JSP整合到 Struts框架中。在Struts中经过标签订义方式的JSP页面可以将用户经过表单输入的数据存入一个JavaBean中,也就是咱们前面提到的 ActionForm bean。经过Action类调用(自动或手动)ActionForm的校验方法来检查用户输入的数据,若是发现不合法的数据,再经过Struts的一个 通用机制将错误信息返回给用户显示。 Struts框架提供了若干个标签库,它们有各自不一样的用途。因为这些库还能够脱离Struts框架单独使用,这样咱们也能够在其余系统中尝试使用这些标签库,它们包括: * struts-html - 这个标签库用来建立动态的HTML页面和表单。 * struts-bean - 提供了相似甚至更强于中的功能。 * struts-logic - 用于在页面输出文本信息时的条件、循环等流程的控制。 * struts-template - 用于产生有共同风格的动态JSP页面模板。 此外,可定制标签库在Struts中还有一大用处是,经过资源文件的方式来实现应用系统的多语言特性,应用Struts的系统若想将系统中的用户交互信息换一种语言的会很简单,更换一个不一样的资源文件就能够了。 你们都开始应用Struts吧! Struts框架可能对于大多数开发人员来讲,是一门比较新的技术。但咱们如今已经能够在很多的应用系统中看到Struts的身影了,而咱们大可在新的应用或正在开发的JSP项目中使用Struts框架。 例 如,在做者如今正在为客户开发的一个大型数据库应用系统中,商业逻辑都是经过EJB来实现的,用户界面则是JSP页面。在struts- config.xml文件中定义了用户输入表单和对应的Action类,当一个请求发生时,即用户数据以ActionForm的形式封装提交到 Action时,Action先调用ActionForm的校验方法,数据检查校验经过后,Action再调用相应的EJB中的方法来完成数据操做,操做 的结果以XML的形式返回,XML解析后再放入咱们数据的封装传递JavaBean - ActionForm中显示到JSP页面里返回用户。 整个的控制流程(包括Action调用后的不一样的返回结果)都尽在struts-config.xml中所掌握,这种“中央集权”的方式很是便于应用流程的调整。而无论是Servlet仍是JSP页面中(甚至在一些n层的应用架构)都无需撰写如何获取显示数据的代码。 由 于目前做者所开发的是一个较大型的系统,有不少的JSP页面和用户要提交的ActionForm类型,所以发现Struts的一个麻烦的地方,那就是:我 们要为如此多页面和ActionForm开发对应的Action类来完成控制,由于咱们目前JSP和ActionForm与Action是一对一的关系。 不过我认为若是在项目前期分析和设计时多下些功夫,作出更完美一些的设计方案的话,这样的状况是能够避免的,固然,在新产品的开发过程当中,想一步就把全部 需求弄清楚明白那也是不可能的。咱们不是都有这样的经历吗?在开发中的应用系统正一步一步走向成熟的时候,更新和更明确的需求才会被提出来。不过,像咱们 手里这个利用Struts开发了六个月的系统也确实少见了,呵呵。除去这些非技术因素不谈,Struts框架为咱们实现MVC模式节省了大量的时间,而且 开发出的系统至关的稳定,能够说是很成熟的产品了。 在本系列文章的第二部分,咱们将把各小段代码集成起来,完成一个完整的Struts应用的实例,但愿你们继续和做者一块儿学习Struts! |
|
||
Jakarta Struts学习之应用实践 接上一篇:Jakarta Struts学习之新手上路 本 文是三篇学习Struts框架系列文章的第二篇。在本系列的的第一篇中,咱们大体浏览了Struts框架,框架的功能以及框架中应用到的各个模块。而本 文,我将利用Struts 1.0为你们演示创建一个简单的应用;在第三篇文章中将介绍如何利用Struts的标签在JSP中访问ApplicationResource文件中的信 息。 咱们在这篇文章将会一步一步的讲解Struts的应用,以这样的形式打开Struts一道道神秘的大门,经过这样的过程,相信也能激起你在应用开发中如何 应用Struts的灵感。若是你对Struts的一些术语不是很清楚的话,能够参考本系列前一篇对Struts做大致介绍的文章。 再次 重复一遍,本文须要读者有以下几方面的知识和经验:JSP,Servlets,自定义标签库(Custom Tag libraries)和XML。此外,在本文中,我还会用到Jakarta项目组其余一些好东东,好比 Tomcathttp://jakarta.apache.org/tomcat/index.html(实现Java Servlet和JSP官方标准的Servlet容器,通俗的讲就是一个JSP的Web Server啦)和Anthttp://jakarta.apache.org/ant/index.html(基于Java的自动编译发布工具,这但是 好东东啊)。 做为一名一直使用前沿技术开发了诸多应用的技术人员,我一直坚信掌握新技术,理解该技术开发的逻辑是相当重要的。但这每每 就是陷住咱们学习步伐的泥潭,正因如此,我打算将利用Struts开发的一套完整流程做为咱们教学的案例。该流程的这个案例可谓“麻雀虽小、五脏据全”, 你彻底能够将这个流程应用到你手头那些复杂庞大的项目中,至少在咱们的大项目中应用这个流程效果不错。 有开发复杂商业应用的开发人员都知道,客户的需求老是在不停变幻,因此若是有一套规范的开发流程来遵循,当客户提出新的需求时,咱们至少能够明确哪些“无理”需求实际上是合理可行的。好,接下里我将在个人这个例子中向各位展现和应用整个流程。 本 文中的示例代码是StrutsSample应用中的一部分,包括build.xml的完整代码能够到此处 [url]http://www.onjava.com/onjava/2001/10/31/examples /StrutsPartII.jar[/url]下载。 Struts开发过程 从Struts发布的版本号能够看出,Struts是个新玩意,她有好几个部分组成,明智的你若是搞清楚了什么时候该开发完成合适的部分,那将会更好的利用咱们的开发时间。从我所开发的几个利用Struts应用中,我大体总结出以下这个比较有效的开发步骤: 1,明确应用需求; 2,由用户输入和获取数据的角度出发,明确和设计出每个用户界面; 3,肯定用户界面的进入路径; 4,由应用逻辑信息肯定动做映射表(ActionMapping); 5,由设计完成的用户界面开发其所用到的类和应用函数; 6,由用户界面中的数据信息开发ActionForm和相应的数据校验方法; 7,ActionMapping中将会被调用相应的Action或转到相应的JSP页面,这一步咱们先开发这些Action; 8,开发商业应用逻辑,就是相应的JavaBean、EJB或其余东东; 9,开发由ActionMapping定义的系统工做流程完成对应的JSP页面; 10,完成系统配置文件:struts-config.xml和web.xml; 11,编译/测试/发布。 明确应用需求 开发任何应用系统的第一步就是收集用户需求信息。无论一个用户逻辑初看上去多么合理,但总有可能在开发时才发现它比看上去要可贵多。因此,建议拟一份明确的用户需求列表,这不仅是出于开发的目的,还能经过该表分析用户需求以肯定哪些地方可能须要花更多的精力。 在咱们这个StrutsSample项目中,应用需求就是: 做为一个展现Struts框架应用的完整例子,本示例完成的功能是用户登陆。目的只为明确Struts的应用,本示例将不会涉及到通常复杂应用系统中可能应用的安全、数据库、EJB开发等等相关技术。 设计用户界面 这个应用中,包括以下三个用户界面: 1)登陆界面,用于用户名和密码输入; 2)当登陆用户为合法用户时的欢迎界面; 3)当登陆失败时的错误提示界面。 肯定用户界面的进入路径 1)登陆界面做为这个应用的默认页面; 2)欢迎界面只有当成功登陆后才能进入; 3)任何可能发生错误的页面能能够进入错误提示界面; 由 应用逻辑信息肯定ActionMapping ActionMapping为整个应用肯定的“线路图”,在配置文件struts-config.xml对ActionMapping进行定义,经过转发 请求(forward)来理顺应用的处理流程,肯定应用中每一个用户请求对应的动做。 一般咱们在开发过程当中就逐步肯定了ActionMapping所需的信息,开发代码的过程就是在由草稿开始一步步完善struts-config.xml 的过程。当Action类处理完用户请求后,其返回的的forward就是在ActionMapping中定义的一个。一个Action返回的 forward彻底有多种可能,尽管一个Action通常只定义其相关的几个forward。那么,若是有多个Action均可能返回的同一个 forward,那么就能够将其定义为全局转发(global forward)。这相似于C中的头文件中全局变量,若是在struts-config.xml描述信息中,某一个forward并非在当前 Action描述中定义的而是全局定义的,那么这个全局的将起做用,一样,一个Action中当前定义的forward将覆盖全局定义。在咱们所给的这个 简单实例中,咱们定义了全局forward D D“error”,当某Action返回的forward是“error”这个映射,那么Errorpage.jsp页面将会显示给用户,尽管当前 Action并无对其定义。 咱们继续不断的开发,项目日渐完善,项目相关的配置文件也会愈来愈详细。在下面的例子中,咱们将以StrutsSample中用到的struts- confug.xml文件为例,学习global forward和一个Action中相关映射的定义。下面定义了一个名为“login”的Action,其为 com.oreilly.actions.LoginAction的实例,当Action处理用户登陆成功后将一个名为"success"的 forward返回,用户也就会看到Welcome.jsp页面,若是登陆失败,Action将返回对应的forward以再显示Login.jsp给用 户,而若是处理过程当中发生其余错误,Action将返回全局定义的forward D D“error”,用户也就会看到错误提示页面Errorpage.jsp。 <!-- ========== Global Forward 定义 --> <global-forwards> <forward name="login" path="/Login.jsp"/> <forward name="error" path="/Errorpage.jsp"/> </global-forwards> <!-- ========== Action Mapping 定义 --> <action-mappings> <!-- <action>元素的相关属性 --> <!-- 如下只列出经常使用属性,其余请参考org.apache.struts.action.ActionMapping的相关文档 path - 当前Action对应的用户请求URI路径 type - 实现当前Action的Java class的完整名字 name - 当前Action中用到的ActionForm的名字,其具体信息在配置文件其余地方另有详细定义 unknown - 若是将该属性设置为true,那么就是声明这个Action将处理整个应用中全部未找到相应处理Action的请求,固然,一个应用系统中也只会有一个Action的unknown属性能够设为true scope - Action中所用到的ActionForm的生存期,能够为“request”或“session”,随着生存期的设置,该Action也会在相应的时间被建立 input - 该Action中相关ActionForm获取用户输入的输入页面,当将ActionForm设为自动验证输入数据,发现不合法数据返回错误时,将返回该页面 validate - 若是本属性为true则在Action动做以前其对应的ActionForm的validate方法会自动被调用,通常用以验证用户输入的数据 forward 元素 - 定义当前Action相关的ActionForward --> <!-- =================== --> <!-- O‘Reilly Struts Sample Main Actions --> <!-- =================== --> <action path="/login" type="com.oreilly.actions.LoginAction" name="loginForm" scope="request" input="/Login.jsp"> <forward name="success" path="/Welcome.jsp"/> <forward name="failure" path="/Login.jsp"/> </action> </action-mappings> 在 前一篇文章中,咱们曾说过,struts-config.xml就是MVC模式的的Controller。在肯定struts-config.xml中的 配置信息时,应该多花些时间精力在上面,以保证每个Action定义及其相关定义是符合应用的需求的。若是在项目开始没有详细的设计其定义,当将全部代 码和配置集成到一块儿的时候,咱们将不可避免的将各部分的代码和配置彻底从新组织一遍。 咱们当前的例子StrusSample由于只是处理用户登陆,因此只须要一个Action。一个应用系统中所要用到的Action的多少彻底依应用的大小 而定。一旦整套Action的映射彻底的定义出来后,咱们就能够一个一个开发其具体实现的Action和ActionForm类,并逐渐将完成的部分一点 一点集成起来。 由设计完成的用户界面开发其所用到的类和应用函数 全部ActionForm的实现类都是org.apache.struts.ActionForm的子类。一个ActionForm是与页面上的输入表单 相关联的,并且ActionForm的实现还能够对用户输入数据的合法性进行验证。做为一个Java Bean,ActionForm有Set和Get方法,当一个页面中表单被提交时,系统将自动调用Set方法将数据放入ActionForm中,而Get 方法将为在Action中操做这些数据所提供。通常来讲,处理表单中的全部数据,并进行合法性验证都彻底能够交由ActionForm来完成。在应用中, 就我我的而言,倾向于将ActionForm和Action划分到不一样的包中,由于当一个页面中要用到几对ActionFrom和Action时,都放在 一个包内会混淆的。下面的代码,就是实例中登陆页面用到的ActionForm的代码。 /* * LoginForm.java */ package com.oreilly.forms; import javax.servlet.http.HttpServletRequest; import org.apache.struts.action.ActionError; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionMapping; /** * 验证用户要用到的两个数据 * * username - 登陆用户名 * password - 用户密码 * */ public final class LoginForm extends ActionForm { private String userName = null; private String password = null; /** * userName的Get方法 * @return String */ public String getUserName() { return (userName); } /** * userName的Set方法 * @param userName */ public void setUserName(String newUserName) { userName = newUserName; } /** * password的Get方法 * @return String */ public String getPassword() { return (password); } /** * password的Set方法 * @param password */ public void setPassword(String newPassword) { password = newPassword; } /** * 重置全部数据 * * @param mapping 当前的ActionMapping * @param request 当前Server正在处理的HttpServletRequest */ public void reset(ActionMapping mapping, HttpServletRequest request) { userName = null; password = null; } /** * 验证当前HTTP请求提交上来的数据 * 若是数据验证发现不合法数据,将返回一个封装 * 全部验证错误的ActionErrors对象 * 若是数据验证经过,该方法返回null或者一个 * 没有封装任何验证错误的ActionErrors对象 * * @param mapping 当前的ActionMapping * @param request 当前Server正在处理的HttpServletRequest */ public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) { ActionErrors errors = new ActionErrors(); // 当前ActionForm中,只须要检查用户输入的用户名数据 if( userName == null || userName.length()==0 ){ errors.add("userName",new ActionError("error.userName.required")); } return (errors); } } 以 上的代码,只有两点和通常的Java Bean有所不一样。其一是reset方法,方法中设置的值将在表单被reset时反应到其对应的表单项上,即将表单项的数据恢复到默认值。其二是 validate方法,是用来验证用户在表单中所输入数据的方法。在当前这个例子中,咱们只验证用户输入的用户名。由于一个用户名其对应的密码可能为空, 因此咱们的逻辑就是验证时不去检查密码。验证用户名,当发现输入的用户名为空时,方法就会产生一个错误对象(ActionError)。 在 Struts中用ActionErrors来装载多个错误,从ActionErrors结尾的那个“s”就能够知道她是一个ActionError对象的 集合。在验证用户输入时,能够验证完表单中全部数据后,再将可能发现的多个错误经过ActionErrors返回给用户,这样的逻辑应该是想固然的啦,不 可能用户有五个不一样的输入错误,却要分五次提示,让用户修改提交五遍吧,呵呵。 同时,要知道在咱们这个例子中,咱们将错误信息提示给用 户是经过ApplicationResource.properties文件。这个文件在Tomcat启动时经过web.xml中的定义为这个应用所使 用。一般每个应用都在其WEB-INF目录下都有web.xml文件来描述系统,而关于部署应用时具体的结构信息,请参考 Tomcathttp://jakarta.apache.org/tomcat/index.html等Server相关的用户手册。 ApplicationResource.properties 文件中能够定义应用中所要用到的提示信息的字符串,字符串都经过一个键值来惟一肯定其位置。在咱们这个例子中,键值 error.userName.required所对应的字符串信息是“A username is required”,在给用户显示错误信息时,也就经过键值肯定的错误提示显示该字符串。经过这样的机制,为咱们在系统中实现多语言提供了便利,将该文件 中的这些字符串翻译成相应的语言,咱们的系统就能够实现西班牙语、德语、法语和汉语等等语言的版本了。 下面这些ApplicationResource.properties中的信息对于咱们这个简单的示例中已经够用了: login.title=Login Struts Sample error.userName.required=A username is required error.login.authenticate=Invalid username/password errors.footer=</ul><hr> errors.header=<h3><font color="red">Page Validation</font></h3>Please correct the following error(s) before contiuing:<ul> applicationResources=Cannot load application resources bundle {0} 页面的标题,按钮或其余什么须要文本提示的地方均可以经过这个文件来定义显示用字符串。咱们将在该系列的最后一篇文章,也就是后续几个开发步骤中讲解如何经过Struts的标签从这个文件中获取显示用字符串。 待续 |
|
||
Jakarta Struts学习之实战演示 本 文是三篇学习Struts框架系列文章的最后一篇。在第一篇文章《Jakarta Struts简介》中,我大体分析了Struts框架,讨论了它所能完成的功能,还浏览了组成Struts的各个组成部分。在第二篇文章《学习 Jakarta Struts》中,我开始详细描述如何利用Struts来构建一个简单应用的过程步骤。而本篇文章将会向你们演示如何将 ApplicationResource文件中的文本信息,经过Struts标签在JSP页面中显示出来。 Action类是链接Struts架 构和应用中业务逻辑代码的桥梁。因此你应该尽量让Action类小巧简单,由于真实应用中的逻辑处理应该是由单独分离出来的逻辑层来完成的。若是你正在 从事n层应用的开发,你固然但愿层与层之间的接口越简单越好。而事实上,Action类中的主要方法"perform()"(1.1中为 execute())却有点暗示应该在本方法中作点什么的意思。咱们知道,每一个Action类都须要从 org.apache.struts.action.Action 继承而来。在小型应用中,咱们的Action类极可能就只要继承org.apache.struts.action.Action就足够了;而在某些特定 的复杂应用中,我就从咱们所实现的Action类中总结出来了一些通用特性。所以,在我看来,构造一个基类将这些通用特性的代码实现出来,让应用中所用到 的全部Action类不直接继承org.apache.struts.action.Action,而继承这个完成了一些通用特性的基类以实现代码重用, 是一个至关不错的设计。我在StrutsSample中就应用了这种方法,构造了这样的一个基类,该基类的方法在完成复杂逻辑的和简单转发请求的 Action类中均可以使用。 package com.oreilly.actions; import java.io.IOException; import java.util.Properties; import java.util.ResourceBundle; import java.util.MissingResourceException; import java.util.Enumeration; import java.util.Properties; import java.rmi.RemoteException; import javax.ejb.EJBHome; import javax.ejb.CreateException; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts.action.Action; import org.apache.struts.action.ActionServlet; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; 这 个类就是使用Struts开发时,全部Action类都要继承的基类。它把一些一般在实际应用中最有可能被用到的东西都考虑进来了。就这篇文章而言, 类中一些与Struts并非太紧密相关的方法将只作注释而不会完整的实现,而从事开发工做的你,有兴趣的话,请完成这些方法并应用这个类,将为你在实际 项目中的开发马不停蹄。注意,由于全部的Action类都要从org.apache.struts.action.Action 继承而来,因此咱们的这个类一样。 public abstract class AbstStrutsActionBase extends Action { / * 定义一些在struts-config.xml中记录在案的 * 全局应用中皆可可通用的forward标识*/ protected static final String SUCCESS = "success"; protected static final String FAILURE = "failure"; protected static final String ERROR = "error"; protected static final String LOGIN = "login"; protected static final String CONFIRM = "confirm"; protected Context jndiContext = null; /** * 默认构造方法 */ public AbstStrutsActionBase() { } /** 下面这个查找EJB实例的方法将不会完整实现。 一 般来讲,Action类应该调用实现了应用的商务逻辑的EJB会话bean(或仅仅普通JavaBean)。在大型项目中,开发人员必须划清层与层之间的 界限。在Action类中,咱们应该拿到获取含有JNDI信息的环境的实例,而后经过EJB的JNDI名字去查询获取它的home接口。过程并不简单,所 如下面这个代码片段只是个给出了必要实现的小例子。 参数类型String,传入的要查询JNDI的名字 返回类型Object,即查找到的home接口 若是查找失败,抛出NamingException异常 若是获取资源信息失败,抛出MissingResourceException异常 */ public Object lookup(String jndiName) throws NamingException, MissingResourceException { // 为调用EJB对象,经过构建记录JNDI信息的Properties对象 // 来得到初始环境信息 if (jndiContext == null) { ResourceBundle resource = ResourceBundle.getBundle("strutssample.properties"); Properties properties = new Properties(); properties.setProperty( Context.INITIAL_CONTEXT_FACTORY, resource.getString(Context.INITIAL_CONTEXT_FACTORY)); properties.setProperty( Context.PROVIDER_URL, resource.getString(Context.PROVIDER_URL)); properties.setProperty( Context.SECURITY_PRINCIPAL, resource.getString(Context.SECURITY_PRINCIPAL)); properties.setProperty( Context.SECURITY_CREDENTIALS, resource.getString(Context.SECURITY_CREDENTIALS)); jndiContext = new InitialContext(properties); } 注意:在真正的产品中,咱们应该在此处考虑代码的健壮性,将代码加入到try/catch块内,并记录全部错误或重要信息到系统log中。而本例中,咱们仅仅把异常往外抛,并假定必定会找到EJB对象的home接口并返回。 return (jndiContext.lookup(jndiName)); } 因为Action类将是由Struts来调用的。因此它的主要方法应该是一个抽象方法,而由每一个继承的子类来具体实现,或者在其中作一些全部Action都会作的通用机制,例如记录log信息。在本例中,咱们一切从简,将其抽象之。 参数mapping:其类型为ActionMapping,将在本Action作跳转选择用 参数actionForm:由Struts根据本次HTTP请求数据填充完成的ActionForm对象(可选,若是存在请求数据的话) 参数request:此Action全部处理的本次HTTP请求(对象) 参数response:此Action输出数据所要用到的HTTP响应(对象) 若是有I/O错误出现,则本方法抛出IOException异常 若是处理时发生servlet异常,则本方法抛出ServletException异常 本方法处理完请求后按照处理逻辑返回相应的页面导向(对象) public abstract ActionForward perform( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException; } 或者让这个抽象方法更有用一点,那就在里面干点什么吧,好比像下面这样在其中记录log。 { ActionForward forward = null; // 只是简单的记录一些提示信息到servlet log getServlet().log( "AbstStrutsActionBase.perform() [Action Class: " + this.getClass().getName() + " ]"); getServlet().log( "AbstStrutsActionBase.perform() [Form Class : " + (form == null ? "null" : form.getClass().getName()) + " ]"); } 而后,咱们再编写的每一个Action类都应该从AbstStrutsActionBase继承,并依照处理逻辑编写各自的perform方法。让咱们用LoginAction为例,看看具体应该怎么应用吧。 package com.oreilly.actions; import java.io.IOException; import java.rmi.RemoteException; import javax.ejb.CreateException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts.action.ActionError; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionForward; import com.oreilly.forms.LoginForm; /* LoginAction 将演示一个Action将如何被Struts架构所调用 在这个例子中,咱们只是简单的演示perform方法是如何调用、执行并返回的 */ public class LoginAction extends AbstStrutsActionBase { 接下来这个是验证用户的方法,本例中没有具体实现。但一个典型的应用方案是调用JavaBean或者EJB来完成。用来查找EJB的lookup方法(在基类中完成的)应该在本方法中被调用,其返回一个依据后台数据库验证用户的接口。 参数类型String,要验证的用户名 参数类型String,密码 返回类型boolean,若是验证经过为true,不然为false public boolean authenticate(String username, String password) { /* 本方法将先作一个查找动做,得到验证用户的EJB对象的接口并调用 * 因为本例只演示Action与商务逻辑层是如何交互的 * 因此具体实现代码本例中就不提供了:) */ return (true); } 接下来咱们在LoginAction中重载基类的perform方法。 参数mapping:其类型为ActionMapping,将在本Action作跳转选择用 参数actionForm:由Struts根据本次HTTP请求数据填充完成的ActionForm对象(可选,若是存在请求数据的话) 参数request:此Action全部处理的本次HTTP请求(对象) 参数response:此Action输出数据所要用到的HTTP响应(对象) 若是有I/O错误出现,则本方法抛出IOException异常 若是处理时发生servlet异常,则本方法抛出ServletException异常 本方法处理完请求后按照处理逻辑返回相应的页面导向(对象) public ActionForward perform( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // 先假定验证失败,那么要导向的forward固然是LOGIN了(见基类定义的全局变量) boolean validLogin = false; ActionForward actionForward = mapping.findForward(LOGIN); // 构造出承载ActionError对象的容器——errors,以备错误出现时可用 ActionErrors errors = new ActionErrors(); // 从由本次请求构造的ActionForm中提取出所须要的数据 LoginForm loginForm = (LoginForm)form; String userName = null; String password = null; if (loginForm != null) { userName = loginForm.getUserName(); password = loginForm.getPassword(); validLogin = authenticate(userName, password); } if (validLogin) { // 验证成功了,导向到struts-config.xml中定义的SUCCESS actionForward = mapping.findForward(SUCCESS); // 存点必要的东东到session,以备后用 request.getSession(true).setAttribute("USERNAME", userName); } else { errors.add("login", new ActionError("error.login.authenticate")); } // 系统若是用户界面友好一点,咱们就应该将错误信息存入request对象中 // 而后到页面,经过在Struts的标签显示出来 if (!errors.empty()) { saveErrors(request, errors); } // 本Action处理完成,导向到合适的forward return (actionForward); } } 注意,这个LoginAction类就是在struts-config.xml中定义的用来处理登陆事务的一个具体实现。当这个类被载入并有一个对象实例化后,Struts架构就会调用它的perform方法。这个方法是这样声明的: public ActionForward perform( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException 其中,mapping是一个记录与此Action对应的forward导向的对象,form对象封装由客户端提交的此Action要处理的数据,还有标准的HttpServletRequest对象和HttpServletResponse对象。 有 了这些对象的辅助,此Action就能够拿到须要的东东顺利开工了。咱们的例子中,要处理的数据主要是用户名和密码,这些都由form对象提供。实现验证 功能是本应用的主要业务逻辑,在方法中的具体实现应该是去取EJB的相应接口来操做或者直接去拿数据库数据来验证。前面那个 AbstStrutsActionBase类中已经实现了一个简单的EJB接口查找动做,因此若是咱们是在开发一个基于EJB实现的系统,它的可重用性就 很是强了。 由验证方法(authenticate())的返回值,Action要接着作出合理的动做。若是验证经过,就要让用户进入正 确的页面,那么咱们就将一些后面可能会用到的信息存入request对象(译注:准确的讲,代码中是存到了session对象里,固然session对象 是和当前request相关的),并向Struts返回success这个forward。这个forward是在struts-config.xml中 定义的,而后由ActionMapping封装起来,在Action处理中能够从中拿出合适的forward作为返回值。若是回头去看看struts- config.xml中的定义,就会知道success这个forward会将用户导向至Welcome.jsp这个页面的。若是验证失败,则将一个错误 信息存起来,而后导向到一个错误提示页面显示出来。 开发应用的业务逻辑 在一个真实的应用系统中,咱们应该将业务逻辑 层整合进来了。在咱们这个例子里,咱们就应该去开发LoginAction中的authenticae方法所调用到的EJB了。可是正如你所见的,咱们完 全能够把这一层暂时屏蔽掉,而利用Struts把前端部分构建并可以让它跑起来的。我其实至关推崇的是方法是先将应用框架搭建并运行起来,而后在开发后台 实际的业务逻辑层。在应用框架彻底恰当的构建起来的时候,后台的开发工做全部作的debug工做也少的多了。并且,业务逻辑的开发也不是本文所要函概的范 围,因此此处咱们略过,不过我相信你如今必定对应用的全局有了整体的把握了吧! 开发由ActionMapping定义的系统工做流程,完成对应的JSP页面 终 于能够将全部这些东东整合在一块儿了。在struts-config.xml配置文件中定义的那些ActionMapping,咱们要完成这些 ActionMapping定义用到的JSP页面。本例中,包括Login.jsp、Welcome.jsp和Errorpage.jsp。还有,尽管我 们在本例中都是将Action处理完成forward到JSP页面,这在这个简单的例子中是再恰当不过的逻辑流程了,而在实际利用Struts开发应用中 呢,固然能够从Action forward到其余的Action。咱们这个简单的Login.jsp页面内容是这样的: <%@ page language="java" %> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <%@ taglib uri="/WEB-INF/struts-form.tld" prefix="form" %> <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %> <html> <head> <title><bean:message key="login.title"/></title> </head> <body> <html:errors/> <h3>Enter your username and password to login:</h3> <html:form action="login.action" focus="userName" > <html:text property="userName" size="30" maxlength="30"/> <html:password property="password" size="16" maxlength="16" redisplay="false"/> <html:submit property="submit" value="Submit"/> <html:reset/> </html:form> </body> </html> Struts在JSP自定义标签库的基础上提供了一套综合各类功能的标签库。利用这些标签库很容易的构建用户界面了。使用这些标签库的好处之一就是能够利用其提供的不少附加功能。好比在通常的JSP页面的表单里咱们能够看到这样常见的HTML片段: <input type="text" name="userName" value=""> 若是咱们使用Struts的标签库的话,就能够改为这样子: <html:text property ="userName"> 不过咱们得如今页面中先声明Struts标签库的定义。 <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> 在 这个例子中,咱们会用到一些Struts标签,但我不许备在此详细讲解Struts各类标签库的用法。相信在你不断使用Struts搭建功能复杂的JSP 页面的过程当中,你将会对所使用过的标签愈来愈熟悉的。到那时,你也将更能体会到Struts标签的益处,利用它们大大的缩短你的开发时间。目前,你能够从 Struts Developers Guides了解到更多的细节。 在咱们这个简单例子中,有两个重点。其一: <title><bean:message key="login.title"/></title> 这就是在利用咱们前面提到的资源文件ApplicationResource来在页面显示信息,而不是将信息文本硬编码到咱们的应用中。 其二: <html:errors/> 这就是在页面中显示出ActionErrors的信息,也就是咱们在LoginForm的验证方法和LoginAction中产生的报错信息的集合对象。 页面中的表单,利用Struts,咱们将用以下的标签来定义: <html:form action="login.action" focus="userName"> 这 里的login.action,是和struts-config.xml中定义ActionMapping相匹配的。在页面标签中这样的定义,就将相关的 Action、ActionForm和ActionForward完整的串了起来。当这个用标签订义的表单提交的时候,Struts中的 ActionServlet就会将其交由login.action来处理。具体的过程咱们下面慢慢深刻。 在Welcome.jsp中,咱们只演示如何将Action中的信息传递到页面加以利用的通常机制: <html> <title>Welcome to Struts</title> <body> <p>Welcome <%= (String)request.getSession().getAttribute("USERNAME") %></p> </p>You have logged in successfully!</p> </body> </html> 还记得吗?咱们在LoginAction中的perform()方法中将USERNAME放到了session中哦。 完成系统配置文件 我 们已经就struts-config.xml谈了好多了。一般,这个文件中的信息会在开发过程当中逐渐完善。可是到了开发过程的最后一部,咱们更应该回头去 检查这个相当重要的配置文件,以保证万无一失:Action、JSP页面还有ActionForm都应该在文件中正确的定义。此外,咱们还不得不说到 web.xml。这个文件是JSP容器(例如Tomcat)获取应用相关配置的重要文件。咱们这个StrutsSample例子所用到的web.xml大 致是这样的: <?xml version="1.0" encoding="ISO-8859-1"?> <!-- This is the web-app configuration that allow the strutsSample to work under Apache Tomcat. --> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd";;> <web-app> <servlet> <servlet-name>oreilly</servlet-name> <servlet-class>org.apache.struts.action.ActionServlet</servlet-class> <init-param> <param-name>application</param-name> <param-value>com.oreilly.ApplicationResources</param-value> </init-param> <init-param> <param-name>config</param-name> <param-value>/WEB-INF/struts-config.xml</param-value> </init-param> <init-param> <param-name>debug</param-name> <param-value>2</param-value> </init-param> <init-param> <param-name>detail</param-name> <param-value>2</param-value> </init-param> <init-param> <param-name>validate</param-name> <param-value>true</param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>oreilly</servlet-name> <url-pattern>*.action</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>Login.jsp</welcome-file> </welcome-file-list> <!-- Struts Tag Library Descriptors --> <taglib> <taglib-uri>/WEB-INF/struts.tld</taglib-uri> <taglib-location>/WEB-INF/struts.tld</taglib-location> </taglib> <taglib> <taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri> <taglib-location>/WEB-INF/struts-bean.tld</taglib-location> </taglib> <taglib> <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri> <taglib-location>/WEB-INF/struts-html.tld</taglib-location> </taglib> <taglib> <taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri> <taglib-location>/WEB-INF/struts-logic.tld</taglib-location> </taglib> <taglib> <taglib-uri>/WEB-INF/struts-form.tld</taglib-uri> <taglib-location>/WEB-INF/struts-form.tld</taglib-location> </taglib> </web-app> 这 里的标签订义了org.apache.struts.action.ActionServlet,并且在本例中,咱们把这个定义的servlet叫做 “oreilly”,并传了两个初始化参数给它:其一是咱们为这个应用所需的显示字符串定义的资源文件,其二是指明struts-config.xml文 件的位置。相信你也注意到了,在中为这个Servlet指明的相应请求处理串是*.action,这是和咱们在页面中的表单定义的提交的URL是吻合的。 也就是说,咱们经过标签告诉Tomcat,全部后缀为.action的请求都交给“oreilly”这个Servlet来处理。你固然能够指定你喜欢的后 缀。在Struts附带的例子中,你可能会看到一般以.do作为后缀,不过我认为.action更明确一些。标签中定义了本应用初始显示页面。最后呢,我 们还要把会用到的Struts标签库列在后面。 编译/测试/发布 到此为止,编译/测试/发布应用以前的全部工做都完 成了。用Ant来编译整个应用是至关容易的。若是你之前没有接触过Ant,那最好把这个研究一下。其实学习和应用Ant来管理一个应用编译环境并不难。我 把这个编译应用所要用到的build.xml和例子放到了一块儿,这篇文章所要用到的全部东东,你均可以点此下载,到时候你到build.xml所在目录简 单执行ant命令就能够完成编译,并打包成strutsSample.war包。固然要执行ant,你得先去下载Ant。将Ant下载回来并搭建好环境可 能得花十几分钟的时间哦。 本应用的目录结构以下: StrutsSample根目录 *.jsp WEB-INF目录 Struts配置文件(struts-config.xml, web.xml) classes目录(仍是以Java程序文件包结构为路径) lib目录(struts.jar) 拿 到了应用的war包,咱们就将它放到Tomcat的webapps路径下,而后启动Tomcat。war包会被自动展开,此应用的上下文环境也会由 Tomcat自动创建起来。咱们经过web.xml告知Tomcat这个应用所需的其余资源在哪里。如今,咱们能够经过 [url]http://localhost:8080/strutsSample[/url]来访问咱们的应用了。若是没有特别指定的话,Tomcat 默认的端口是8080,咱们定义的默认初始页面Login.jsp也将显示出来,如今咱们来试试吧。 结论 经过本系列 的文章,咱们利用Struts从应用需求开始,一步步将整个应用搭建起来。和普通的JSP技术相比,经过Struts开发的应用涉及到更多的与之相关的各 类文件,也正是依靠各种文件,咱们才可能构建一个适合开发复杂应用的MVC架构。咱们的第一个Struts应用花了如此多的时间,是为了要弄清楚 Struts的各个部分究竟是如何工做的。 但愿本系列Struts文章,可以帮助你了解Struts是由哪些部分构成的,它们可以完成什么,也但愿介绍一个比较好的开发流程可供你参考。Struts才诞生不久,我有信心它将成为咱们构建J2EE应用的优秀工具。 做者简介: Sue Spielman是ONJava.com的副编辑,主要擅长于JSP和Servlet技术,她仍是Switchback Software LLC公司的总裁和高级技术咨询专家。 |
|
||
这东西,国外早就淘汰了的 |
|
||
[quote]原帖由 [i]风云孤独[/i] 于 2006-8-27 18:06 发表 这东西,国外早就淘汰了的 [/quote] ........ |
|
||
[quote]原帖由 [i]风云孤独[/i] 于 2006-8-27 18:06 发表 这东西,国外早就淘汰了的 [/quote] 不至于吧,如今咱们给鬼子作东西都还用这个啊 也许如今有新技术了,可是struts仍是挺不错的 |
|
||
[quote]原帖由 [i]风云孤独[/i] 于 2006-8-27 18:06 发表 这东西,国外早就淘汰了的 [/quote] 好像目前最流行的三个是struts,webwork,spring mvc. struts的下一代框架还不成熟吧. 估计还会流行一段时间. |
|
||
如今就国内有市场,学这个建议开始时别抱着书啃,多看看标签,logic html bean之类的,学点javascript、实用的sql之类的东西 最基础的东西了 还有多作项目才是硬道理 刚开始不要急着学hibernate和spring 虽然那个东西很方便,但屁事儿也多 只是建议~ |
|
||
俺决定不学J2EE了,作了一段时间就烦了 |