浅谈struts、spring、Hibernian

来源:互联网 发布:html编程工具 编辑:程序博客网 时间:2024/05/01 23:23

 

Java流行框架浅谈

 

1

Struts的起源

  Struts最早是作为Apache Jakarta项目的组成部分,项目的创立者希望通过对该项目的研究,改进和提高JavaServer Pages Servlet、标签库以及面向对象的技术水准。Struts这个名字来源于在建筑和旧式飞机中使用的支持金属架。这个框架之所以叫"Struts",是为了提醒我们记住那些支撑我们房屋,建筑,桥梁,甚至我们踩高跷时候的基础支撑。这也是一个解释Struts在开发Web应用程序中所扮演的角色的精彩描述。当建立一个物理建筑时,建筑工程师使用支柱为建筑的每一层提供支持。同样,软件工程师使用Struts为业务应用的每一层提供支持。它的目的是为了帮助我们减少在运用MVC设计模型来开发Web应用的时间。我们仍然需要学习和应用该架构,不过它将可以完成其中一些繁重的工作。如果想混合使用ServletsJSP的优点来建立可扩展的应用,Struts是一个不错的选择。

  早期Smalltalk 程序语言便采用了MVC(Model-View -Controller) 模式( Patterns ) 以增加程序代码弹性,MVC模式将程序代码整理切割为三部份,Model 部分是业务与应用领域( Business domain) 相关逻辑、管理状态之对象,Controller 部分接收来自View 所输入的资料并与Model 部分互动,是业务流程控制( Flow Control) 之处,View 部分则负责展现资料、接收使用者输入资料。在Java 应用中,JFC/SwingAWTJSP 皆是可用作View 之技术规格,而JavaBean Enterprise JavaBean 规格则可用于Model 程序代码,一旦应用程序以MVC 模式加以适当之分割,Model 部分程序代码可在不同使用者接口外观之应用程序中重复使用。

  随着JSP Servlet 技术大量应用于以Web 为基础之应用程序,Java 开发人员群体认为应以较佳之模式以提升Web 应用程序之可维护性与重复使用性。早期JSP 规格书中曾列举两种可行之JSP 应用架构,分别为Model1 Model 2

  在Model 1 架构中,JSP 直接处理Web 浏览器送来之请求( Request ),并辅以JavaBean 处理应用相关逻辑。Model 1 架构单纯编写比较容易,但在Model 1 JSP 可能同时肩负View Controller 角色,两类程序代码有可能混杂而不易维护。而Model 2 中将Servlet 纳入架构中扮演前端Controller 角色,将Web 浏览器送出之请求集中送至Servlet Servlet 可集中管理使用者登入、权限控制、多国语言转换等前置处理,再视需求转向给对应之JSP 处理。Model 2 中采用了较佳之MVC 模式,但增加了编写复杂度。

  StrutsApache软件基金下Jakarta项目的一部分。除Struts之外,还有其他成功的开源产品,包括Tomcat Ant Velocity2000 Craig R. McClanahan 先生贡献了他编写的JSP Model 2 架构之Application Framework 原始程序代码给Apache 基金会,成为Apache Jakarta 计划Struts Framework 前身。

  开始的代码基础从20005月开始开发,直到20016月,1.0版本发布。有30 多个开发者参与进来,并有数千人参与到讨论组中。Struts 代码基础由一个志愿的Commnitter团队来管理。到2002年,Struts 小组共有9个志愿Commnitter

  Struts框架的主要架构设计和开发者是Craig R.McClanahanCraig 也是Tomcat 4的主要架构师,以及Java Web Services Developer Pack的主要架构师和实现者。他现在是SunJavaServer Faces (JSR-127) 以及J2EE平台的Web层架构的规范领导。Craig R. McClanahan 先生是JCP ExpertGroup 成员之一,曾参与JSP 规格制定与Tomcat 4 之编写,因此Struts Framework 广受Java 开发人员群体所重视。Borland 2002 年底开始于开发工具JBuilder 中支持Struts Framework

  StrutsApache 基金会Jakarta 项目组的一个Open Source 项目,它采用MVC模式,能够很好地帮助java 开发者利用J2EE开发Web应用。和其他的java架构一样,Struts 也是面向对象设计,将MVC模式"分离显示逻辑和业务逻辑"的能力发挥得淋漓尽致。Structs 框架的核心是一个弹性的控制层,基于如 Java ServletsJavaBeansResourceBundlesXML等标准技术,以及 Jakarta Commons 的一些类库。Struts有一组相互协作的类(组件)、Serlvet以及jsp tag lib组成。基于struts构架的web应用程序基本上符合JSP Model2的设计标准,可以说是一个传统 MVC设计模式的一种变化类型。

  Struts最早是作为Apache Jakarta项目的组成部分问世运作。项目的创立者希望通过对该项目的研究,改进和提高Java Server PagesServlet、标签库以及面向对象的技术水准。

  Struts的目的是为了减少在运用MVC设计模型来开发Web应用的时间。你仍然需要学习和应用该架构,不过它将可以完成其中一些繁重的工作。

  StrutsTomcatTurbine等诸多Apache项目一样,是开源软件,这是它的一大优点,使开发者能更深入的了解其内部实现机制。

  除此之外,Struts的优点主要集中体现在两个方面:Taglib和页面导航。TaglibStruts的标记库,灵活动用,能大大提高开发效率。另外,就目前国内的JSP开发者而言,除了使用JSP自带的常用标记外,很少开发自己的标记,或许Struts是一个很好的起点。

  关于页面导航,我认为那将是今后的一个发展方向,事实上,这样做,使系统的脉络更加清晰。通过一个配置文件,即可把握整个系统各部分之间的联系,这对于后期的维护有着莫大的好处。尤其是当另一批开发者接手这个项目时,这种优势体现得更加明显。

  MVCModel-View-Controller的缩写,是一种常用的设计模式。MVC 减弱了业务逻辑接口和数据接口之间的耦合,以及让视图层更富于变化。Struts MVC的一种实现,它将 Servlet JSP 标记(属于 J2EE 规范)用作实现的一部分。Struts继承了MVC的各项特性,并根据J2EE的特点,做了相应的变化与扩展。Struts的工作原理,如图所示:

Struts的工作流程

  服务器启动后,根据web.xml加载ActionServlet读取struts-config.xml文件内容到内存。

  以登陆为例:第一次进login.jsp会先实例化Form、把默认值赋给表单元素。

输入用户名密码提交表单、提交到action属性的login.do,通过ActionServletstruts-config.xml文件找到 action下的path属性找到.do,通过name属性找form-beans中的form-beanname属性得到ActionForm的包名类名,先实例化form,把表单的值填充给form,调用formvalidate方法验证、ActionErrors返回null表示验证通过,否则失败返回input指定的页面.验证通过会实例化Action,执行Actionexcute方法。

Struts框架

  struts框架具有组件的模块化,灵活性和重用性的优点,同时简化了基于MVCweb应用程序的开发。

  本章详细讨论struts架构。我们将看到struts是如何清晰地区分控制,事务逻辑和外观,从而简化了开发应用程序过程的。我们还将介绍struts提供的类如何使得开发工作更加简单,这些类包括:

 控制程序流程的类l  

 实现和执行程序事务逻辑的类l  

 自定义的标记库使得创建和验证HTML表单更加容易l  

  1 Struts压缩包内容

  文件夹jakarta-struts-1.0.2包含两个目录,libwebapps。在lib目录中有使用struts创建应用程序是所需的文件:

  文件 描述

  jdbc2_0-stdext.jar 包含JDBC2.0 Optional Package API类。如果我们要使用struts提供的数据资源,就需要将这个文件拷贝到WEB-INF/lib

  Struts.jar 包含struts中所有的java类。同样也需要拷贝到WEB-INF/lib

  *.tld 标记库描述器文件,描述了多个struts标记库中的自定义标记。同样要拷贝到WEB-INF/lib

  在webapps目录下有如下文件:

  Web应用程序 描述

  Struts-blank.war 一个简单的web应用程序

  Struts-documentation.war 包含struts站点上所有struts文档

  Struts-example.war Struts很多特性的示范

  Struts-exercisetaglib.war 主要用于对自定义标签库进行增加而使用的测试页,但也可以示范如何使用struts标记

  Struts-template.war 包含struts模板标记的介绍和范例

  Struts-upload.war 一个简单的例子,示范如何使用struts框架上传文件

  2.Struts体系结构

  让我们从MVC角度观察struts框架中的组件

  框架中三个部分:模型,视窗和控制器。

  模型

  在struts框架中,模型分为两个部分:

 系统的内部状态l  

 可以改变状态的操作(事务逻辑)l  

  内部状态通常由一组ActinForm JavaBean表示。根据设计或应用程序复杂度的不同,这些Bean可以是自包含的并具有持续的状态,或只在需要时才获得数据(从某个数据库)。

  大型应用程序通常在方法内部封装事务逻辑(操作),这些方法可以被拥有状态信息的bean调用。比如购物车bean,它拥有用户购买商品的信息,可能还有checkOut()方法用来检查用户的信用卡,并向仓库发定货信息。

  小型程序中,操作可能会被内嵌在Action类,它是struts框架中控制器角色的一部分。当逻辑简单时这个方法很适合。

  建议用户将事务逻辑(要做什么)与Action类所扮演的角色(决定做什么)分开。

  视窗

  由JSP建立,struts包含扩展自定义标签库,可以简化创建完全国际化用户界面的过程。

  控制器

  struts中,基本的控制器组件是ActionServlet类中的实例servelt,实际使用的servlet在配置文件中由一组映射(由ActionMapping类进行描述)进行定义。

  3.Struts框架中的组件

  (由于ROSE工具还未能下载,只能找来这幅图,它说明了一定问题,特别是ActionErrors,但它并没有将ActionMappingJSPTag Library包含进来,有时间作完替换)

  框架中所使用的组件:

  ActionServlet 控制器

  ActionClass 包含事务逻辑

  ActionForm 显示模块数据

  ActionMapping 帮助控制器将请求映射到操作

  ActionForward 用来指示操作转移的对象

  ActionError 用来存储和回收错误

  Struts标记库 可以减轻开发显示层次的工作

  下面我们看看各自在框架中所扮演的角色和责任。

  3.1 Struts配置文件

  这是将struts组件结合在一起的东东:struts-config.xml。默认值

  /WEB-INF/struts-config.xml。配置文件可以定义:

 全局转发l  

 ActionMapping 帮助控制器将请求映射到操作l  

 ActionForm bean 显示模块数据l  

 JDBC数据源l  

  配置全局转发

  全局转发用来在JSP页之间创建逻辑名称映射。转发都可以通过对调用操作映射的实例来获得,例如:

  actionMappingInstace.findForward(“logicalName”);

  全局转发的例子:(所有的例子我没有进行解释,一是结合表可以理解,二是例子大部分来自系列四的示例,你应该在作完实验后,再来看一遍)

  <global-forwards>

  <forward name="bookCreated" path="/BookView.jsp"/>

  </global-forwards>

  属性 描述

  Name 全局转发的名字

  Path 与目标URL的相对路径

  配置ActionMapping

  ActionMapping对象帮助进行框架内部的流程控制,它们可将请求URI映射到Action,并且将Action类与ActionForm bean相关联。ActionServlet在内部使用这些映射,并将控制转移到特定Action类的实例。所有Action类使用perform()方法实现特定应用程序代码,返回一个ActionForward对象,其中包括响应转发的目标资源名称。例如:

  <action-mappings>

  <action path="/createBook"

  type="BookAction"

  name="bookForm"

  scope="request"

  input="/CreateBook.jsp">

  </action>

  <forward name=”failure” path=”/CreateBook.jsp”/>

  <forward name=”cancel” path=”/index.jsp”/>

  </action-mappings>

  属性 描述

  Path Action类的相对路径

  Name 与本操作关联的Action bean的名称

  Type 连接到本映射的Action类的全称(可有包名)

  Scope ActionForm bean的作用域(请求或会话)

  Prefix 用来匹配请求参数与bean属性的前缀

  Suffix 用来匹配请求参数与bean属性的后缀

  attribute 作用域名称。

  className ActionMapping对象的类的完全限定名默认的类是org.apache.struts.action.ActionMapping

  input 输入表单的路径,指向bean发生输入错误必须返回的控制

  unknown 设为true,操作将被作为所有没有定义的ActionMappingURI的默认操作

  validate 设置为true,则在调用Action对象上的perform()方法前,ActionServlet将调用ActionForm beanvalidate()方法来进行输入检查

  通过<forward>元素,可以定义资源的逻辑名称,该资源是Action类的响应要转发的目标。

  属性 描述

  Id ID

  ClassName ActionForward类的完全限定名,默认是org.apache.struts.action.ActionForward

  Name 操作类访问ActionForward时所用的逻辑名

  Path 响应转发的目标资源的路径

  redirect 若设置为true,则ActionServlet使用sendRedirect()方法来转发资源

  配置ActionForm Bean

  ActionServlet使用ActionForm来保存请求的参数,这些bean的属性名称与HTTP请求参数中的名称相对应,控制器将请求参数传递到ActionForm bean的实例,然后将这个实例传送到Action类。例子:

  <form-beans>

  <form-bean name="bookForm" type="BookForm"/>

  </form-beans>

  属性 描述

  Id ID

  className ActionForm bean的完全限定名,默认值是org.apache.struts.action.ActionFormBean

  Name 表单bean在相关作用域的名称,这个属性用来将beanActionMapping进行关联

  Type 类的完全限定名

  配置JDBC数据源

  用<data-sources>元素可以定义多个数据源。

  属性 描述

  Id ID

  Key Action类使用这个名称来寻找连接

  Type 实现JDBC接口的类的名称

  下面属性需要<set-property>元素定义,在框架1.1版本中已不在使用,但你可用<data-source>元素。例子:

  <data-sources>

  <data-source id=”DS1”

  key=”conPool”

  type=”org.apache.struts.util.GenericDataSource”

  <set-property id=”SP1”

  autoCommit="true"

  description="Example Data Source Configuration"

  driverClass="org.test.mm.mysql.Driver"

  maxCount="4"

  minCount="2"

  url="jdbc:mysql://localhost/test"

  user="struts"

  password="wrox" />

  <data-source/>

  </data-sources>

  属性 描述

  desciption 数据源的描述

  autoCommit 数据源创建的连接所使用的默认自动更新数据库模式

  driverClass 数据源所使用的类,用来显示JDBC驱动程序接口

  loginTimeout 数据库登陆时间的限制,以秒为单位

  maxCount 最多能建立的连接数目

  minCount 要创建的最少连接数目

  password 数据库访问的密码

  readOnly 创建只读的连接

  User 访问数据库的用户名

  url JDBCURL

  通过指定关键字名称,Action类可以访问数据源,比如:

  javax.sql.DataSource ds = servlet.findDataSource(“conPool”);

  javax.sql.Connection con = ds.getConnection();

  3.2 ActionServlet

  框架中的控制器组件是有org.apache.struts.action.ActionServlet类实现的,这个类是javax.servlet.http.HttpServlet类的扩展。

  Struts controller基本功能是:

  1. 截获用户的Http请求

  2. 把这个请求映射到相应的Action类,如果这是此类收到的第一个请求,将初始化实例并缓存。

  3. 创建或发现一个ActionForm bean实例(看配置文件是否定义),然后将请求过程移植到bean.

  4. 调用Action实例的perform()方法并将ActioForm bean,Action Mapping对象,requestresponse对象传给它。

  如:public ActionForword perform(ActionMapping mapping,

  ActionForm form,

  HttpServletRequest request,

  HttpServletResponse response)

  5.perform返回一个ActionForword对象,此对象连接到相应的jsp页面.

  ActionServlet配置

  我们需要在web.xml中声明ActionServlet,并且将它配置成启动时进行加载。以下为可以配置的初始化参数:

  参数 默认值 描述

  application null 应用程序的资源集合的类

  bufferSize 4096 文件上传的缓冲区大小

  config /WEB-INF/struts-config.xml 配置文件的位置和名称

  content Text/html 默认的内容类型

  debug 0 程序调试的级别

  detail 0 程序调试细节的级别

  factory null 消息资源工厂,用于国际化中解释消息资源

  formBean org.apache.struts.action.ActionFormBean 封装ActionForm bean信息的类的名称

  forward org.apache.struts.action.ActionForward 封装ActionForward对象信息的类的名称

  locale true true,将在用户会话中存储一个本地对象

  mapping org.apache.struts.action.ActionForward 封装ActionMapping信息的类的名称

  maxFileSize 250M 上传文件的最大尺寸

  multipartClass org.apache.struts.action.ActionForward 处理多部分请求的类的名称

  noCache False HTTP标头是否要设置为禁止缓寸

  Null True 设置为true,对于无效的信息关键字将返回null

  tempDir 作为一个servlet参数提供给程序的工作目录 处理下载文件是使用的临时工作目录

  validate True 是否使用新格式的配置文件

  vallidating True 是否对配置文件进行有效性分析

  大多数情况下,标准的servlet就能够满足用户需要。

  第一次收到特定请求的URI时,ActionServlet将适当的Action类进行实例化,然后ActionServletAction类实例中以servlet为变量名存储一个引用。当被实例化后,Action类会被暂存以备再用。

  ActionServlet也提供一些方法,由Action类用来访问数据源和转发目标之类的资源。

  ActionServlet方法

  ActinServlet提供了一组能够被Action对象使用的方法。

  Struts API的全部信息在struts-documentation.war中可以找到。动态的添加或删除,这些方法只影响应用程序当前的实例:

  public void addFormBean(ActionFormBean formBean)

  public void removeFormBean(ActionFormBean formBean)

  public void addForward(ActionForward actionForward)

  public void removeForward(ActionForward actionForward)

  public void addMapping(ActionMapping actionMapping)

  public void removeMapping(ActionMapping actionMapping)

  根据名称查找对象:

  public ActionFormBean findFormBean(String name)

  public ActionForward findForward(String name)

  public ActionMapping findMapping(String name)

  用来处理数据源:

  public void addDataSource(String key , DataSource ds)

  public DataSource findDataSource(String key)

  我们还可以:

 使用destroy()方法结束ActionServletl  

 使用reload()方法从struts配置文件将信息重新加载。l  

  3.3 ActionMapping

  将特定请求映射到特定Action的相关信息存储在ActionMapping中,ActionServeltActionMapping传送到Action类的perform()方法,Action将使用ActionMappingfindForward()方法,此方法返回一个指定名称的ActionForward,这样Action就完成了本地转发。若没有找到具体的ActionForward,就返回一个null.

  public ActionForward findForward(String name)

  可在映射中动态添加ActionForward:

  public void addForward(ActionForward forward)

  可返回与映射关联的表单bean:

  public String getName()

  可返回映射的属性域(会话或请求)

  public String getScope()

  3.4 Action

  Action类真正实现应用程序的事务逻辑,它们负责处理请求。在收到请求后,ActionServlet会:

 为这个请求选择适当的Actionl  

 如果需要,创建Action的一个实例l  

 调用Actionperform()方法l  

  如果ActionServlet不能找到有效的映射,它会调用默认的Action(在配置文件中定义)。如果找到了ActionServlet将适当的ActionMapping类转发给Action,这个Action使用ActionMapping找到本地转发,然后获得并设置ActionMapping属性。根据servlet的环境和被覆盖的perform()方法的签名,ActionServlet也会传送ServletRequest对象或HttpServletRequest对象。

  所有Action类都扩展org.apache.struts.action.Action类,并且覆盖类中定义的某一个perform()方法。有两个perform()方法:

  处理非HTTP(一般的)请求:

  public ActionForward perform(ActionMapping action,

  AcionForm form,

  ServletRequest request,

  ServletResponse response)

  throws IOException,ServletException

  处理HTTP请求:

  public ActionForward perform(ActionMapping action,

  AcionForm form,

  HttpServletRequest request,

  HttpServletResponse response)

  throws IOException,ServletException

  Action类必须以线程安全的方式进行编程,因为控制器会令多个同时发生的请求共享同一个实例,相应的,在设计Action类时就需要注意以下几点:

 不能使用实例或静态变量存储特定请求的状态信息,它们会在同一个操作中共享跨越请求的全局资源l  

 如果要访问的资源(如JavaBean和会话变量)在并行访问时需要进行保护,那么访问就要进行同步l  

  Action类的方法

  除了perform()方法外,还有以下方法:

  可以获得或设置与请求相关联的区域:

  public Locale getLocale(HttpServletRequest request)

  public void setLocale(HttpServletRequest request,Locale locale)

  为应用程序获得消息资源:

  public MessageResources getResources()

  检查用户是否点击表单上的取消键,如果是,将返回true:

  public Boolean isCancelled(HttpServletRequest request)

  当应用程序发生错误时,Action类能够使用下面方法存储错误信息:

  public void saveErrors(HttpServletRequest request,ActionErrors errors)

  ActionError实例被用来存储错误信息,这个方法在错误关键字下的请求属性列表中存储ActionError对象。通过使用在struts标记库中定义的自定义标记,JSP页能够显示这些错误信息,稍后我们就介绍。

  3.5 ActionForm

  框架假设用户在应用程序中为每个表单都创建了一个ActionForm bean,对于每个在struts-config.xml文件中定义的bean,框架在调用Action类的perform()方法之前会进行以下操作:

l   在相关联的关键字下,它检查用于适当类的bean实例的用户会话,如果在会话中没有可用的bean,它就会自动创建一个新的bean并添加到用户的会话中。

 对于请求中每个与bean属性名称对应的参数,Action调用相应的设置方法。l  

 Action perform()被调用时,最新的ActionForml   bean传送给它,参数值就可以立即使用了。

  ActionForm类扩展org.apache.struts.action.ActionForm类,程序开发人员创建的bean能够包含额外的属性,而且ActionServlet可能使用反射(允许从已加载的对象中回收信息)访问它。

  ActionForm类提供了另一种处理错误的手段,提供两个方法:

  Public ActionErrors validate(ActionMappin mapping,

  ServletRequest request)

  Public ActionErrors validate(ActionMappin mapping,

  HttpServletRequest request)

  你应该在自己的bean里覆盖validate()方法,并在配置文件里设置<action>元素的validatetrue。在ActionServlet调用Action类前,它会调用validate(),如果返回的ActionErrors不是null,则ActinForm会根据错误关键字将ActionErrors存储在请求属性列表中。

  如果返回的不是null,而且长度大于0,则根据错误关键字将实例存储在请求的属性列表中,然后ActionServlet将响应转发到配置文件<action>元素的input属性所指向的目标。

  如果需要执行特定的数据有效性检查,最好在Action类中进行这个操作,而不是在ActionForm类中进行。

  方法reset()可将bean的属性恢复到默认值:

  public void reset(ActionMapping mapping,HttpServletRequest request)

  public void reset(ActionMapping mapping,ServletRequest request)

  典型的ActionFrom bean只有属性的设置与读取方法(getXXX,而没有实现事务逻辑的方法。只有简单的输入检查逻辑,使用的目的是为了存储用户在相关表单中输入的最新数据,以便可以将同一网页进行再生,同时提供一组错误信息,这样就可以让用户修改不正确的输入数据。而真正对数据有效性进行检查的是Action类或适当的事务逻辑bean

  3.6 ActionForward

  目的是控制器将Action类的处理结果转发至目的地。

  Action类获得ActionForward实例的句柄,然后可用三种方法返回到ActionServlet,所以我们可以这样使用findForward():

 ActionServlet根据名称获取一个全局转发l  

 ActionMappin实例被传送到perform()方法,并根据名称找到一个本地转发l  

  另一种是调用下面的一个构造器来创建它们自己的一个实例:

  public ActionForward()

  public ActionForward(String path)

  public ActionForward(String path,Boolean redirect)

  3.7 错误处理

  struts提供了两个类来处理错误:ActionErrorsActionError,它们都扩展org.apache.struts.actionActionErrors保存着ActionError对象的集合,其中每一个代表了独立的错误信息。每个ActionError都包含了关键字,能够映射到资源文件中存储的错误信息,而这个资源文件是在ActionServlet初始化参数中指定的。

  ActionError

  ActionError类定义了一组重载的构造器来创建错误信息,第一个构造器方法使用一个字符串作为参数,例如:

  ActionError error = new ActionError(“error.Invalid”);

  实例error映射到应用程序资源文件中的一个错误消息:

  error.invalid=Invalid Number

  如果在JSP页使用<html:error>,用户就会看见加粗的Invalid Number

  另一种使用了java.text.MessageFormat类,可在消息中指定替换字符串,例如:

  error.invalid=Invalid Number

  创建一个错误消息:

  ActionError error = new ActionError(‘error.invalid’,new Double(-1));

  JSP页显示:Invalild Number –1

  还有获得特定消息的错误关键字:

  public String getKey()

  还有获得替换字符串数组:

  public String[] getValues()

  ActionError

  ActionError类从不独立进行错误处理,它们总是被存储在ActionErrors对象中。ActionErrors对象保存ActionError类的集合以及它们特定的属性值,我们可以使用自己定义的属性值,或是使用ActionErrors.GLOBAL_ERROR.

  下面是典型Action类的perform()中错误处理情况:

  MyForm form = (MyForm) form;

  if (number == -1) {

  ActionErrors errors = new ActionErrors();

  ActionError error = new ActionError(“error.Invalid”,new Double(-1));

  errors.add(ActionErrors.GLOBAL_ERROR,error);

  saveErrors(req,errors);

  String input = mapping.getInput();

  Return new ActionForward(input);

  }

  ActionErrors有如下有用方法:

  方法 描述

  clear() 清除所有错误信息

  empty() 如果ActionErrors对象是空的,它返回true

  get() 返回错误信息。若无参数,所有信息将作为一个Iterator对象返回

  properties() 返回包含属性名称的Iterator,这些属性至少有一个错误

size() 返回错误的数目(整型数)

2

 

 

 

 

 

Spring的起源和背景

  Rod Johson2002年编著的《Expert one to one J2EE design and development》一书中,对Java EE正统框架臃肿、低效、脱离现实的种种现状提出了质疑,并积极寻求探索革新之道。以此书为指导思想,他编写了interface21框架,这是一个力图冲破Java EE传统开发的困境,从实际需求出发,着眼于轻便、灵巧,易于开发、测试和部署的轻量级开发框架。Spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004324,发布了1.0正式版。同年他又推出了一部堪称经典的力作《Expert one-to-one J2EE Development without EJB》,该书在Java世界掀起了轩然大波,不断改变着Java开发者程序设计和开发的思考方式。在该书中,作者根据自己多年丰富的实践经验,对EJB的各种笨重臃肿的结构进行了逐一的分析和否定,并分别以简洁实用的方式替换之。至此一战功成,Rod Johnson成为一个改变Java世界的大师级人物。

  传统J2EE应用的开发效率低,应用服务器厂商对各种技术的支持并没有真正统一,导致J2EE的应用没有真正实现Write OnceRun Anywhere的承诺。Spring作为开源的中间件,独立于各种应用服务器,甚至无须应用服务器的支持,也能提供应用服务器的功能,如声明式事务等。

  Spring致力于J2EE应用的各层的解决方案,而不是仅仅专注于某一层的方案。可以说Spring是企业应用开发的一站式选择,并贯穿表现层、业务层及持久层。然而,Spring并不想取代那些已有的框架,而与它们无缝地整合。

Spring简介

  Spring是一个开源框架,它由Rod Johnson创建。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。

             SpringFramework的组成

  目的:解决企业应用开发的复杂性

  功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能

  范围:任何Java应用

  简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。

  轻量——从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。

  控制反转——Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoCJNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。

  面向切面——Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务()管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。

  容器——Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。

  框架——Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。

  所有Spring的这些特征使你能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础支持。

为什么需要Spring

  你可能正在想“Spring不过是另外一个的framework”。当已经有许多开放源代码(和专有) J2EE framework时,我们为什么还需要Spring Framework

  Spring是独特的,因为若干个原因:

  它定位的领域是许多其他流行的framework没有的。Spring关注提供一种方法管理你的业务对象。

   Spring是全面的和模块化的。Spring有分层的体系结构,这意味着你能选择使用它孤立的任何部分,它的架构仍然是内在稳定的。因此从你的学习中,你可得到最大的价值。例如,你可能选择仅仅使用Spring来简单化JDBC的使用,或用来管理所有的业务对象。

  它的设计从底部帮助你编写易于测试的代码。Spring是用于测试驱动工程的理想的framework

  Spring对你的工程来说,它不需要一个以上的frameworkSpring是潜在地一站式解决方案,定位于与典型应用相关的大部分基础结构。它也涉及到其他framework没有考虑到的内容。

Spring带给我们什么

  方便解耦,简化开发

  通过Spring提供的IoC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。有了Spring,用户不必再为单实例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。

  AOP编程的支持

  通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付。

  声明式事务的支持

  在Spring中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。

  方便程序的测试

  可以用非容器依赖的编程方式进行几乎所有的测试工作,在Spring里,测试不再是昂贵的操作,而是随手可做的事情。

  方便集成各种优秀框架

  Spring不排斥各种优秀的开源框架,相反,Spring可以降低各种框架的使用难度,Spring提供了对各种优秀框架(如Struts,HibernateHessionQuartz)等的直接支持。

  降低Java EE API的使用难度

  Spring对很多难用的Java EE API(如JDBCJavaMail,远程调用等)提供了一个薄薄的封装层,通过Spring的简易封装,这些Java EE API的使用难度大为降低。

  Java 源码是经典学习范例

  Spring的源码设计精妙、结构清晰、匠心独用,处处体现着大师对Java设计模式灵活运用以及对Java技术的高深造诣。Spring框架源码无疑是Java技术的最佳实践范例。如果想在短时间内迅速提高自己的Java技术水平和应用开发水平,学习和研究Spring源码将会使你收到意想不到的效果。

Spring框架的好处

  在我们进入细节以前,让我们看一下Spring可以给一个工程带来的一些好处:

  Spring能有效地组织你的中间层对象,无论你是否选择使用了EJB。如果你仅仅使用了Struts或其他的包含了J2EE特有APIsframework,你会发现Spring关注了遗留下的问题,。

  Spring能消除在许多工程上对Singleton的过多使用。根据我的经验,这是一个主要的问题,它减少了系统的可测试性和面向对象特性。

  Spring能消除使用各种各样格式的属性定制文件的需要,在整个应用和工程中,可通过一种一致的方法来进行配置。曾经感到迷惑,一个特定类要查找迷幻般的属性关键字或系统属性,为此不得不读Javadoc乃至源编码吗?有了Spring,你可很简单地看到类的JavaBean属性。倒置控制的使用(在下面讨论)帮助完成这种简化。

  Spring能通过接口而不是类促进好的编程习惯,减少编程代价到几乎为零。

  Spring被设计为让使用它创建的应用尽可能少的依赖于他的APIs。在Spring应用中的大多数业务对象没有依赖于Spring

  使用Spring构建的应用程序易于单元测试。

  Spring能使EJB的使用成为一个实现选择,而不是应用架构的必然选择。你能选择用POJOslocal EJBs来实现业务接口,却不会影响调用代码。

  Spring帮助你解决许多问题而无需使用EJBSpring能提供一种EJB的替换物,它们适于许多web应用。例如,Spring能使用AOP提供声明性事务而不通过使用EJB容器,如果你仅仅需要与单个的数据库打交道,甚至不需要JTA实现。

  ■Spring为数据存取提供了一致的框架,不论是使用JDBCO/R mapping产品(如Hibernate)。

  Spring确实使你能通过最简单可行的解决办法解决你的问题。这些特性是有很大价值的。

  总结起来,Spring有如下优点:

  低侵入式设计,代码污染极低

   独立于各种应用服务器,可以真正实现Write Once,Run Anywhere的承诺

  SpringDI机制降低了业务对象替换的复杂性

  Spring并不完全依赖于Spring,开发者可自由选用Spring框架的部分或全部

Spring能做什么?

Spring带来的好处:让我们可以 专心做事

  Spring提供许多功能,在此我将快速地依次展示其各个主要方面。

  首先,让我们明确Spring范围。尽管Spring覆盖了许多方面,但我们已经有清楚的概念,它什么应该涉及和什么不应该涉及。

  Spring的主要目的是使J2EE易用和促进好编程习惯。

  Spring不重新开发已有的东西。因此,在Spring中你将发现没有日志记录的包,没有连接池,没有分布事务调度。这些均有开源项目提供(例如Commons Logging 用来做所有的日志输出,或Commons DBCP用来作数据连接池),或由你的应用程序服务器提供。因为同样的的原因,我们没有提供O/R mapping层,对此,已有有好的解决办法如HibernateJDO

  Spring的目标是使已存在的技术更加易用

  例如,尽管我们没有底层事务协调处理,但我们提供了一个抽象层覆盖了JTA或任何其他的事务策略。

  Spring没有直接和其他的开源项目竞争,除非我们感到我们能提供新的一些东西。例如,象许多开发人员,我们从来没有为Struts高兴过,并且感到在MVC web framework中还有改进的余地。在某些领域,例如轻量级的IoC容器和AOP框架,Spring有直接的竞争,但是在这些领域还没有已经较为流行的解决方案。(Spring在这些区域是开路先锋。)

  Spring也得益于内在的一致性。

  所有的开发者都在唱同样的的赞歌,基础想法依然是Expert One-on-One J2EE设计与开发的那些。

  并且我们已经能够使用一些主要的概念,例如倒置控制,来处理多个领域。

  Spring在应用服务器之间是可移植的。

  当然保证可移植性总是一次挑战,但是我们避免任何特定平台或非标准化,并且支持在WebLogicTomcatResinJBossWebSphere和其他的应用服务器上的用户。

3

 

 

 

 

 

 


Hibernate介绍

  Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSPWeb应用中使用,最具革命意义的是,Hibernate可以在应用EJBJ2EE架构中取代CMP,完成数据持久化的重任。

  Hibernate的核心接口一共有5个,分别为:SessionSessionFactoryTransactionQueryConfiguration。这5个核心接口在任何开发中都会用到。通过这些接口,不仅可以对持久化对象进行存取,还能够进行事务控制。下面对这五的核心接口分别加以介绍。

  ·Session接口:Session接口负责执行被持久化对象的CRUD操作(CRUD的任务是完成与数据库的交流,包含了很多常见的SQL语句。)。但需要注意的是Session对象是非线程安全的。同时,Hibernatesession不同于JSP应用中的HttpSession。这里当使用session这个术语时,其实指的是Hibernate中的session,而以后会将HttpSesion对象称为用户session

  ·SessionFactory接口:SessionFactroy接口负责初始化Hibernate。它充当数据存储源的代理,并负责创建Session对象。这里用到了工厂模式。需要注意的是SessionFactory并不是轻量级的,因为一般情况下,一个项目通常只需要一个SessionFactory就够,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory

  ·Configuration接口:Configuration接口负责配置并启动Hibernate,创建SessionFactory对象。在Hibernate的启动的过程中,Configuration类的实例首先定位映射文档位置、读取配置,然后创建SessionFactory对象。

  ·Transaction接口:Transaction接口负责事务相关的操作。它是可选的,开发人员也可以设计编写自己的底层事务处理代码。

·QueryCriteria接口:QueryCriteria接口负责执行各种数据库查询。它可以使用HQL语言或SQL语句两种表达方式。

 

Hibernate执行过程

 

Hibernate主键介绍

  Assigned

  Assigned方式由程序生成主键值,并且要在save()之前指定否则会抛出异常

  特点:主键的生成值完全由用户决定,与底层数据库无关。用户需要维护主键值,在调用session.save()之前要指定主键值。

  Hilo

  Hilo使用高低位算法生成主键,高低位算法使用一个高位值和一个低位值,然后把算法得到的两个值拼接起来作为数据库中的唯一主键。Hilo方式需要额外的数据库表和字段提供高位值来源。默认请况下使用的表是

  hibernate_unique_key,默认字段叫作next_hinext_hi必须有一条记录否则会出现错误。

  特点:需要额外的数据库表的支持,能保证同一个数据库中主键的唯一性,但不能保证多个数据库之间主键的唯一性。Hilo主键生成方式由Hibernate 维护,所以Hilo方式与底层数据库无关,但不应该手动修改hi/lo算法使用的表的值,否则会引起主键重复的异常。

  Increment

  Increment方式对主键值采取自动增长的方式生成新的主键值,但要求底层数据库的支持Sequence。如OracleDB2等。需要在映射文件xxx.hbm.xml中加入Increment标志符的设置。

  特点:由Hibernate本身维护,适用于所有的数据库,不适合多进程并发更新数据库,适合单一进程访问数据库。不能用于群集环境。

  Identity

  Identity当时根据底层数据库,来支持自动增长,不同的数据库用不同的主键增长方式。

  特点:与底层数据库有关,要求数据库支持Identity,如MySQl中是auto_increment, SQL Server 中是Identity,支持的数据库有MySqlSQL ServerDB2SybaseHypersonicSQL Identity无需Hibernate和用户的干涉,使用较为方便,但不便于在不同的数据库之间移植程序。

  Sequence

  Sequence需要底层数据库支持Sequence方式,例如Oracle数据库等

  特点:需要底层数据库的支持序列,支持序列的数据库有DB2PostgreSqlQracleSAPDb等在不同数据库之间移植程序,特别从支持序列的数据库移植到不支持序列的数据库需要修改配置文件

  Native

  Native主键生成方式会根据不同的底层数据库自动选择IdentitySequenceHilo主键生成方式

  特点:根据不同的底层数据库采用不同的主键生成方式。由于Hibernate会根据底层数据库采用不同的映射方式,因此便于程序移植,项目中如果用到多个数据库时,可以使用这种方式。

  UUID

  UUID使用128UUID算法生成主键,能够保证网络环境下的主键唯一性,也就能够保证在不同数据库及不同服务器下主键的唯一性。

  特点;能够保证数据库中的主键唯一性,生成的主键占用比较多的存贮空间

  Foreign GUID

  Foreign用于一对一关系中。GUID主键生成方式使用了一种特殊算法,保证生成主键的唯一性,支持SQL ServerMySQL

Hibernate源码中几个包的作用简要介绍

  net.sf.hibernate.*  

  该包的类基本上都是接口类和异常类

  net.sf.hibernate.cache.*  

  JCS的实现类

  net.sf.hibernate.cfg.*  

  配置文件读取类

  net.sf.hibernate.collection.*  

  Hibernate集合接口实现类,例如ListSetBag等等,Hibernate之所以要自行编写集合接口实现类是为了支持lazy loading

  net.sf.hibernate.connection.*  

  几个数据库连接池的Provider

  net.sf.hibernate.dialect.*  

  支持多种数据库特性,每个Dialect实现类代表一种数据库,描述了该数据库支持的数据类型和其它特点,例如是否有AutoIncrement,是否有Sequence,是否有分页sql等等

  net.sf.hibernate.eg.*  

  Hibernate文档中用到的例子

  net.sf.hibernate.engine.*  

  这个包的类作用比较散

  net.sf.hibernate.expression.*  

  HQL支持的表达式

  net.sf.hibernate.hq.*  

  HQL实现

  net.sf.hibernate.id.*  

  ID生成器

  net.sf.hibernate.impl.*  

  最核心的包,一些重要接口的实现类,如果SessionSessionFactoryQuery

  net.sf.hibernate.jca.*  

  JCA支持,把Session包装为支持JCA的接口实现类

  net.sf.hibernate.jmx.*  

  我不懂JMX,只知道JMX是用来编写App Server的管理程序的,大概是JMX部分接口的实现,使得App Server可以通过JMX接口管理Hibernate

  net.sf.hibernate.loader.*  

  也是很核心的包,主要是生成sql语句的

  net.sf.hibernate.lob.*  

  BlobClob支持

  net.sf.hibernate.mapping.*  

  hbm文件的属性实现

  net.sf.hibernate.metadata.*  

  POMeta实现

  net.sf.hibernate.odmg.*  

  ODMG是一个ORM标准,这个包是ODMG标准的实现类

  net.sf.hibernate.persister.*  

  核心包,实现持久对象和表之间的映射

  net.sf.hibernate.proxy.*  

  ProxyLazy Loading支持

  net.sf.hibernate.ps.*  

  该包是PreparedStatment Cache

  net.sf.hibernate.sql.*  

  生成JDBC sql语句的包

  net.sf.hibernate.test.*  

  测试类,你可以用junit来测试Hibernate

  net.sf.hibernate.tool.hbm2ddl.*  

  用hbm配置文件生成DDL

  net.sf.hibernate.transaction.*  

  Hibernate Transaction实现类

  net.sf.hibernate.type.*  

  Hibernate中定义的持久对象的属性的数据类型

  net.sf.hibernate.util.*  

  一些工具类,作用比较散

  net.sf.hibernate.xml.*  

  XML数据绑定

缓存管理

  Hibernate 中提供了两级Cache,第一级别的缓存是Session级别的缓存,它是属于事务范围的缓存。这一级别的缓存由hibernate管理的,一般情况下无需进行干预;第二级别的缓存是SessionFactory级别的缓存,它是属于进程范围或群集范围的缓存。这一级别的缓存可以进行配置和更改,并且可以动态加载和卸载。 Hibernate还为查询结果提供了一个查询缓存,它依赖于第二级缓存。

  1. 一级缓存和二级缓存的比较:第一级缓存 第二级缓存 存放数据的形式 相互关联的持久化对象 对象的散装数据 缓存的范围 事务范围,每个事务都有单独的第一级缓存进程范围或集群范围,缓存被同一个进程或集群范围内的所有事务共享 并发访问策略由于每个事务都拥有单独的第一级缓存,不会出现并发问题,无需提供并发访问策略由于多个事务会同时访问第二级缓存中相同数据,因此必须提供适当的并发访问策略,来保证特定的事务隔离级别 数据过期策略没有提供数据过期策略。处于一级缓存中的对象永远不会过期,除非应用程序显式清空缓存或者清除特定的对象必须提供数据过期策略,如基于内存的缓存中的对象的最大数目,允许对象处于缓存中的最长时间,以及允许对象处于缓存中的最长空闲时间 物理存储介质内存内存和硬盘。对象的散装数据首先存放在基于内在的缓存中,当内存中对象的数目达到数据过期策略中指定上限时,就会把其余的对象写入基于硬盘的缓存中。缓存的软件实现 HibernateSession的实现中包含了缓存的实现由第三方提供,Hibernate仅提供了缓存适配器(CacheProvider)。用于把特定的缓存插件集成到Hibernate中。启用缓存的方式只要应用程序通过Session接口来执行保存、更新、删除、加载和查询数据库数据的操作,Hibernate就会启用第一级缓存,把数据库中的数据以对象的形式拷贝到缓存中,对于批量更新和批量删除操作,如果不希望启用第一级缓存,可以绕过Hibernate API,直接通过JDBC API来执行指操作。用户可以在单个类或类的单个集合的粒度上配置第二级缓存。如果类的实例被经常读但很少被修改,就可以考虑使用第二级缓存。只有为某个类或集合配置了第二级缓存,Hibernate在运行时才会把它的实例加入到第二级缓存中。 用户管理缓存的方式第一级缓存的物理介质为内存,由于内存容量有限,必须通过恰当的检索策略和检索方式来限制加载对象的数目。Sessionevit()方法可以显式清空缓存中特定对象,但这种方法不值得推荐。 第二级缓存的物理介质可以是内存和硬盘,因此第二级缓存可以存放大量的数据,数据过期策略的maxElementsInMemory属性值可以控制内存中的对象数目。管理第二级缓存主要包括两个方面:选择需要使用第二级缓存的持久类,设置合适的并发访问策略:选择缓存适配器,设置合适的数据过期策略。

  2. 一级缓存的管理: 当应用程序调用Sessionsave()update()savaeOrUpdate()get()load(),以及调用查询接口的 list()iterate()filter()方法时,如果在Session缓存中还不存在相应的对象,Hibernate就会把该对象加入到第一级缓存中。当清理缓存时,Hibernate会根据缓存中对象的状态变化来同步更新数据库。 Session为应用程序提供了两个管理缓存的方法: evict(Object obj):从缓存中清除参数指定的持久化对象。 clear():清空缓存中所有持久化对象。

  3. 二级缓存的管理:

  3.1. Hibernate的二级缓存策略的一般过程如下:

  1) 条件查询的时候,总是发出一条select * from table_name where …. (选择所有字段)这样的SQL语句查询数据库,一次获得所有的数据对象。

  2) 把获得的所有数据对象根据ID放入到第二级缓存中。

  3) Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;查不到,再查询数据库,把结果按照ID放入到缓存。

  4) 删除、更新、增加数据的时候,同时更新缓存。

  Hibernate的二级缓存策略,是针对于ID查询的缓存策略,对于条件查询则毫无作用。为此,Hibernate提供了针对条件查询的Query Cache

  3.2. 什么样的数据适合存放到第二级缓存中? 1 很少被修改的数据 2 不是很重要的数据,允许出现偶尔并发的数据 3 不会被并发访问的数据 4 参考数据,指的是供应用参考的常量数据,它的实例数目有限,它的实例会被许多其他类的实例引用,实例极少或者从来不会被修改。

  3.3. 不适合存放到第二级缓存的数据? 1 经常被修改的数据 2 财务数据,绝对不允许出现并发 3 与其他应用共享的数据。

  3.4. 常用的缓存插件 Hibernater 的二级缓存是一个插件,下面是几种常用的缓存插件:

  l EhCache:可作为进程范围的缓存,存放数据的物理介质可以是内存或硬盘,对Hibernate的查询缓存提供了支持。

  l OSCache:可作为进程范围的缓存,存放数据的物理介质可以是内存或硬盘,提供了丰富的缓存数据过期策略,对Hibernate的查询缓存提供了支持。

  l SwarmCache:可作为群集范围内的缓存,但不支持Hibernate的查询缓存。

  l JBossCache:可作为群集范围内的缓存,支持事务型并发访问策略,对Hibernate的查询缓存提供了支持。

  3.5. 配置二级缓存的主要步骤:

  1) 选择需要使用二级缓存的持久化类,设置它的命名缓存的并发访问策略。这是最值得认真考虑的步骤。

 2) 选择合适的缓存插件,然后编辑该插件的配置文件。

 

使用Strutsspringhibernate框架技术把我们从繁琐的编码工作中解脱了出来,使我们更能够把精力放在真正需要考虑的事情上,在软件的大规模开发中,提高了项目的生产率,对企业和软件开发行业的贡献是非常巨大的!

 

                                             写作结束日期: 2009-2-10

                                             作者:王传品

                                            

           

注:在论文的编写过程中《百度百科》、《编程之家》、《JavaEye》提供了非常宝贵的资料

 

 

 

 

 

 

 

原创粉丝点击