Eclipse 安装Maven
Help->MarketPlace->search “Maven”->Install“Maven Integration forEclipse WTP (Incubation)” and “Maven Integration for Eclipse”
=>如果不安装这两个,会出现导入工程时丢失 配置信息
=>一开始我只安装了“Maven Integrationfor Eclipse”, 结果出现我导入其他copy过来的项目时丢失信息(WebApp->右键Properties->DeploymentAssembly->Maven Dependencies). 如果丢失在该页面, 可安装如下方法添加(Deployment Assembly)->Add->Java Build PathEntries->选择Maven Dependencies
TOMCAT
提供了servlet功能的服务器,叫做servlet容器. 对web程序来说,servlet容器的作用就相当于桌面程序里操作系统的作用,都是提供一些编程基础设施)
Hibernate
创建一个xml使数据库表和代码对象一一对应
熟悉Struts的读者都知道Struts有一个ActionServlet,用来完成分发器的功能。其实所有的MVC框架都会有一个Servlet来完成这个功能,Spring也不例外,Spring中的分发器就是DispatcherServlet
Appendix A
SSH架构(Struts+Spring+Hibernate)介绍和一个例子
举一个小例子
加入我要盖一件小平房(做一个网站),我需要做的是:
1:买一块地。(租一台服务器)--1天
2:申请一个门牌号码(买一个域名)--1天
3:买材料,请2、3个工人,开始盖房(准备所需要的开发工具IDE什么的,搭建测试环境,找2,3个程序员--刚毕业的大学生就可以了)。--1周
4:盖房(敲代码编程)--1到3个月。
5:房子盖好了,东敲敲西敲敲看牢不牢固(自己测试一下功能都齐全了没)--1周。
6:如果有问题,比方说卧室不够透气,把卧室的墙多开一扇窗户(哪个页面有问题,删除重新写一个)。比方说墙里面的电线发现有问题,把墙凿开,换一根电线。
6:完工。
总共耗时2-4个月左右。
现在我要盖一栋大楼(开发一个企业级项目),本质上还是盖房子,但是如果就像盖小平房一样的去做。结果是怎样的呢?
盖到18楼了,突然说5楼内测的电线堵住了,5楼以上都没有点,于是得把5楼以上的全拆了,拆到5楼,把墙凿开,把电线换一根,再继续往上面盖。
相信没有哪栋大厦是这样盖出来的。
于是有了建筑师(软件架构师)这个职位,有了建筑设计学(软件架构学)这么个说法。
盖大楼,一开始的步骤是这样的。
地还是要买,不过得做土地勘察,样本采集,看地质如何。
然后得画图纸,这图纸一画就是很久,要考虑到整栋大楼的方方面面,哪些墙可以供拆除,就在里面放电线水管什么的。哪些是主力墙不能拆除。这里卖弄的学问太多,笔者也无法弄清楚。
然后就是打地基。这也是相当重要的环节,地基没打好,整个房子都不稳固。然后就是用钢筋水泥等,打造整栋大楼的框架。让房子非常坚固。
再后才是逐步完善大楼内部,一层层的砌砖,一间间地粉刷,装修。就算某一块出了问题。去掉或者修复那一块就行了,整栋大楼屹立不倒,稳稳当当。
企业级项目中,也是同安的过程。
先用UML建模,建立数据库模型,项目的分层架构设计,使用框架让整个项目健壮起来,动一处而不会牵动全身。
struts,spring,hibernate都是为 了让项目更健壮而产生的。如果只是要做一个小网站,我觉得很没有必要使用这些东西,就ASP,PHP一定能做得更快,就像盖小平房一样。就算要用 Java,就用JSP+JavaBean就行了。如果是开发企业级项目,ASP和PHP是绝对不能跟J2EE相提并论的。
Struts是MVC框架,它的作用不是让人能干什么(它能做的事JSP都能做),它的作用是不能让人干什么。就好像,设计师要砌墙工人在哪里砌砖,他就不能去别出砌一样。给程序语言严格的规范,让它按照规范走,不会随心所欲地去编代码。这样可以保证项目的高度一致性。
Spring是J2EE轻量级框架。它的做法好比把项目分成一个个地组件,哪一块出了问题,换掉那一块就是了。别的地方根本不用动。就好像我刚刚举的5楼电线出了问题,就在5楼把墙凿开,换一个电线即可,不用担心5楼的墙凿开上面的会塌下来。
Hibernate是ORM工具,不能称之为框架,它至少至少有一个好处,在项目做移植数据库的时候,不用切换数据库层的代码。当然它的好处很多。笔者在所有的开源技术中,也最钟情对Hibernate的研究。
不过这些问题,都只有在很大的项目开发中才会用到。所以如是是小项目开发,不建议使用J2EE.
Struts
Struts是一个基于Sun J2EE平台的MVC框架,主要是采用Servlet和JSP技术来实现的。Struts框架可分为以下四个主要部分,其中三个就和MVC模式紧密相关:
1、模型(Model),本质上来说在Struts中Model是一个Action类(这个会在后面详细讨论),开发者通过其实现商业逻辑,同时用户请求通过控制器(Controller)向Action的转发过程是基于由struts-config.xml文件描述的配置信息的。
2、视图(View),View是由与控制器Servlet配合工作的一整套JSP定制标签库构成,利用她们我们可以快速建立应用系统的界面。
3、控制器(Controller),本质上是一个Servlet,将客户端请求转发到相应的Action类。
4、一堆用来做XML文件解析的工具包,Struts是用XML来描述如何自动产生一些JavaBean的属性的,此外Struts还利用XML来描述在国际化应用中的用户提示信息的(这样一来就实现了应用系统的多语言支持)。
Spring
Spring是轻量级的J2EE应用程序框架。
Spring的核心是个轻量级容器(container),实现了IoC(Inversion ofControl)模式的容器,Spring的目标是实现一个全方位的整合框架,在Spring框架下实现多个子框架的组合,这些子框架之间彼此可以独立,也可以使用其它的框架方案加以替代,Spring希望提供one-stop shop的框架整合方案。
Spring不会特別去提出一些子框架来与现有的OpenSource框架竞争,除非它觉得所提出的框架夠新夠好,例如Spring有自己的 MVC框架方案,因为它觉得现有的MVC方案有很多可以改进的地方,但它不强迫您使用它提供的方案,您可以选用您所希望的框架来取代其子框架,例如您仍可以在Spring中整合您的Struts框架。
Spring的核心概念是IoC,IoC的抽象概念是「依赖关系的转移」,像是「高层模组不应该依赖低层模组,而是模组都必须依赖于抽象」是 IoC的一种表现,「实现必须依赖抽象,而不是抽象依赖实现」也是IoC的一种表现,「应用程序不应依赖于容器,而是容器服务于应用程序」也是IoC的一种表现。
Spring的架构性的好处
Spring能有效地组织你的中间层对象,无论你是否选择使用了EJB。如果你仅仅使用了Struts或其他的包含了J2EE特有APIs的framework,你会发现Spring关注了遗留下的问题。
Spring能消除在许多工程上对Singleton的过多使用。根据我的经验,这是一个主要的问题,它减少了系统的可测试性和面向对象特性。
Spring 能消除使用各种各样格式的属性定制文件的需要,在整个应用和工程中,可通过一种一致的方法来进行配置。曾经感到迷惑,一个特定类要查找迷幻般的属性关键字或系统属性,为此不得不读Javadoc乃至源编码吗?有了Spring,你可很简单地看到类的JavaBean属性。倒置控制的使用(在下面讨论)帮助完成这种简化。Spring能通过接口而不是类促进好的编程习惯,减少编程代价到几乎为零。
Spring被设计为让使用它创建的应用尽可能少的依赖于他的APIs。在Spring应用中的大多数业务对象没有依赖于Spring。
使用Spring构建的应用程序易于单元测试。
Spring能使EJB的使用成为一个实现选择,而不是应用架构的必然选择。你能选择用POJOs或local EJBs来实现业务接口,却不会影响调用代码。
Spring帮助你解决许多问题而无需使用EJB。Spring能提供一种EJB的替换物,它们适于许多web应用。例如,Spring能使用AOP提供声明性事务而不通过使用EJB容器,如果你仅仅需要与单个的数据库打交道,甚至不需要JTA实现。
Spring为数据存取提供了一致的框架,不论是使用JDBC或O/R mapping产品(如Hibernate)。
Spring确实使你能通过最简单可行的解决办法解决你的问题。这些特性是有很大价值的。
Spring能做什么?
Spring提供许多功能,在此我将快速地依次展示其各个主要方面。
任务描述:
首先,让我们明确Spring范围。尽管Spring覆盖了许多方面,但我们已经有清楚的概念,它什么应该涉及和什么不应该涉及。
Spring的主要目的是使J2EE易用和促进好编程习惯。
Spring 不重新开发已有的东西。因此,在Spring中你将发现没有日志记录的包,没有连接池,没有分布事务调度。这些均有开源项目提供(例如 Commons Logging 用来做所有的日志输出,或Commons DBCP用来作数据连接池),或由你的应用程序服务器提供。因为同样的的原因,我们没有提供O/R mapping层,对此,已有有好的解决办法如Hibernate和JDO。
Spring的目标是使已存在的技术更加易用。例如,尽管我们没有底层事务协调处理,但我们提供了一个抽象层覆盖了JTA或任何其他的事务策略。
Spring没有直接和其他的开源项目竞争,除非我们感到我们能提供新的一些东西。例如,象许多开发人员,我们从来没有为Struts高兴过,并且感到在 MVC web framework中还有改进的余地。在某些领域,例如轻量级的 IoC容器和AOP框架,Spring有直接的竞争,但是在这些领域还没有已经较为流行的解决方案。(Spring在这些区域是开路先锋。)
Spring也得益于内在的一致性。
所有的开发者都在唱同样的的赞歌,基础想法依然是Expert One-on-One J2EE设计与开发的那些。
并且我们已经能够使用一些主要的概念,例如倒置控制,来处理多个领域。
Spring在应用服务器之间是可移植的。
当然保证可移植性总是一次挑战,但是我们避免任何特定平台或非标准化,并且支持在WebLogic,Tomcat,Resin,JBoss,WebSphere和其他的应用服务器上的用户。
Spring的核心即是个IoC/DI的容器,它可以帮程序设计人员完成组件之间的依赖关系注入,使得组件之间的依赖达到最小,进而提高组件的重用性, Spring是个低侵入性(invasive)的框架,Spring中的组件并不会意识到它正置身于Spring中,这使得组件可以轻易的从框架中脱离,而几乎不用任何的修改,反过来说,组件也可以简单的方式加入至框架中,使得组件甚至框架的整合变得容易。
Spring最为人重视的另一方面是支持AOP(Aspect-OrientedProgramming),然而AOP框架只是Spring支持的一个子框架,说Spring框架是AOP框架并不是一件适当的描述,人们对于新奇的 AOP关注映射至Spring上,使得人们对于Spring的关注集中在它的AOP框架上,虽然有所误解,但也突显了Spring的另一个令人关注的特色。
Spring也提供MVC Web框架的解決方案,但您也可以将自己所熟悉的MVC Web框架与Spring解合,像是Struts、Webwork等等,都可以与Spring整合而成为进用于自己的解決方案。Spring也提供其它方面的整合,像是持久层的整合如JDBC、O/R Mapping工具(Hibernate、iBATIS)、事务处理等等,Spring作了对多方面整合的努力,故说Spring是个全方位的应用程序框架。
AJAX
全称“AsynchronousJavaScript and XML”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术。它有机地包含了以下几种技术:基于web标准(standards-based presentation)XHTML+CSS的表示; 使用 DOM(DocumentObject Model)进行动态显示及交互;使用 XML 和 XSLT 进行数据交换及相关操作;使用 XMLHttpRequest 进行异步数据查询、检索;使用 JavaScript 将所有的东西绑定在一起。类似于DHTML或LAMP,AJAX不是指一种单一的技术,而是有机地利用了一系列相关的技术。事实上,一些基于AJAX的“派生/合成”式(derivative/composite)的技术正在出现,如“AFLAX”。
ajax优势
传统的web应用允许用户填写表单(form),当提交表单时就向web服务器发送一个请求。服务器接收并处理传来的表单,然后返回一个新的网页。这个做法浪费了许多带宽,因为在前后两个页面中的大部分HTML代码往往是相同的。由于每次应用的交互都需要向服务器发送请求,应用的响应时间就依赖于服务器的响应时间。这导致了用户界面的响应比本地应用慢得多。与此不同,AJAX应用可以仅向服务器发送并取回必需的数据,它使用SOAP或其它一些基于XML 的web service接口,并在客户端采用JavaScript处理来自服务器的响应。因为在服务器和浏览器之间交换的数据大量减少,结果我们就能看到响应更快的应用。同时很多的处理工作可以在发出请求的客户端机器上完成,所以Web服务器的处理时间也减少了。
Hibernate
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了轻量级的对象封装,使得Java程序员可以使用对象编程思维来操纵数据库。 Hibernate可以在应用EJB的J2EE架构中取代CMP,完成数据持久化。它还可以应用在任何使用JDBC的场合,既可以在Java的客户端程序实用,也可以在Servlet/JSP的Web应用中使用
Hibernate不会对您造成妨碍,也不会强迫您修改对象的行为方式。它们不需要实现任何不可思议的接口以便能够持续存在。惟一需要做的就是创建一份 XML“映射文档”,告诉Hibernate您希望能够保存在数据库中的类,以及它们如何关联到该数据库中的表和列,然后就可以要求它以对象的形式获取数据,或者把对象保存为数据。与其他解决方案相比,它几乎已经很完美了。
运行时,Hibernate读取映射文档,然后动态构建Java类,以便管理数据库与Java之间的转换。在Hibernate中有一个简单而直观的 API,用于对数据库所表示的对象执行查询。要修改这些对象,(一般情况下)只需在程序中与它们进行交互,然后告诉Hibernate保存修改即可。类似地,创建新对象也很简单;只需以常规方式创建它们,然后告诉Hibernate有关它们的信息,这样就能在数据库中保存它们。
Hibernate API学习起来很简单,而且它与程序流的交互相当自然。在适当的位置调用它,就可以达成目的。它带来了很多自动化和代码节省方面的好处,所以花一点时间学习它是值得的。而且还可以获得另一个好处,即代码不用关心要使用的数据库种类(否则的话甚至必须知道)。我所在的公司就曾有过在开发过程后期被迫更换数据库厂商的经历。这会造成巨大的灾难,但是借助于Hibernate,只需要简单地修改Hibernate配置文件即可。
这里的讨论假定您已经通过创建Hibernate映射文档,建立了一个关系数据库,并且拥有要映射的Java类。有一个Hibernate“工具集”可在编译时使用,以支持不同的工作流。例如,如果您已经拥有Java类和映射文档,Hibernate可以为您创建(或更新)必需的数据库表。或者,仅仅从映射文档开始,Hibernate也能够生成数据类。或者,它可以反向设计您的数据库和类,从而拟定映射文档。还有一些用于Eclipse的alpha 插件,它们可以在IDE中提供智能的编辑支持以及对这些工具的图形访问。
如果您使用的是Hibernate 2环境,这些工具鲜有提供,但是存在可用的第三方工具。 使用Hibernate的场合
既然Hibernate看起来如此灵活好用,为什么还要使用其他的工具呢?下面有一些场景,可以帮助您做出判断(或许通过提供一些比较和上下文,可以有助于鉴别非常适用Hibernate的场合)。
如果应用对于数据存储的需要十分简单——例如,您只想管理一组用户优先选择——您根本不需要数据库,更不用说一个优秀的对象-关系映射系统了(即使它也如Hibernate这般易于使用)!从Java 1.4开始,有一个标准的Java Preferences API可以很好地发挥这个作用。(在ONJava文章中可以找到有关Preferences API的更多信息。)
对于熟悉使用关系数据库和了解如何执行完美的SQL查询与企业数据库交互的人来说,Hibernate似乎有些碍手碍脚,这就像带有动力和自动排挡的快艇车会使注重性能的赛车驾驶员不耐烦一样。如果您属于这种人,如果您所在的项目团队拥有一个强大的DBA,或者有一些存储过程要处理,您可能想研究一下 iBATIS。Hibernate的创建者本身就把iBATIS当作是另一种有趣的选择。我对它很有兴趣,因为我们曾为一个电子商务站点开发了一个类似的系统(其功能更为强大),而且从那时到现在,我们已经在其他环境中使用过它,尽管在发现Hibernate之后,在新项目中我们通常更喜欢使用 Hibernate。您可以认为,以SQL为中心的解决方案(比如iBATIS)是“反向的”对象/关系映射工具,而Hibernate是一个更为传统的 ORM。
当然,还有其他的外部原因会导致采用另外的方法。比如,在一个企业环境中,必须使用成熟的EJB架构(或者其他的一些非普通对象映射系统)。可以为提供自己的数据存储工具的平台量身定做代码,比如Mac OS X's Core Data。使用的可能是像XML DTD这样的存储规范,而它根本不涉及关系数据库。
但是,如果您使用的是富对象模型,而且想要灵活、轻松且高效地保存它(无论您是否正要开始或已经决定使用关系数据库,只要这是一个选择——而且存在可用的优秀免费数据库,比如MySQL,或可嵌入Java的HSQLDB,它就应该始终是一个选择),那么Hibernate很可能就是您理想的选择。您可能会惊讶于节省的时间之多,以及您将会多么地喜欢使用它。
用java 来建立一个很有价值的web 应用不是一个简单的任务。在架构这个应用时要考虑很多的因素和问题。从更高的层次来看,开发人员面临着关于如何构建用户接口,何处驻留业务逻辑,以及如何实现数据持久性这些问题。这3层都有各自的问题需要回答。而每一层又需要实现那些技术?应用如何设计来进行松散耦合并能进行灵活变更?应用架构是否允许某一层变更而不影响到其它的层次?应用应该如何处理容器一级的服务比如事务?
为你的应用创建一个架构之前有许多问题需要澄清。幸运的是,有很多开发者都意识到这个问题,并建立了很多框架来解决这些问题。一个良好的框架可以让开发人员减轻重新建立解决复杂问题方案的负担和精力;它可以被扩展以进行内部的定制化;并且有强大的用户社区来支持它。框架通常能很好的解决一个问题。然而,你的应用是分层的,可能每一个层都需要各自的框架。仅仅解决UI问题并不意味着你能够很好的将业务逻辑和持久性逻辑和UI 组件很好的耦合。例如,你不应该使具有JDBC代码的业务逻辑放入控制器之中,这不是控制器应该提供的功能。一个UI 控制器应该是轻量化的组件,由它代表对UI范围之外的其它应用层的服务调用。良好的框架自然地形成代码分离的原则。更为重要的是,框架减轻了开发人员从头构建持久层代码的精力,从而集中精力来应用逻辑上,这对客户端来说更为重要。
本文讨论了如何结合几个著名的框架来达到松散耦合,如何设计你的架构,以及如何达到各个层次的一致性设计。面临的挑战是,将框架整合起来,以使每一层都向另外的层次以一种松散的方式来暴露接口,而不管底层功能使用的是什么技术。本文还讨论整合3种著名开源框架的一种策略。对表现层,我们使用Struts;业务层使用Spring;对于持久层我们使用的是Hibernate。你尽可以取代这里的某个框架而使用你喜欢的框架已达到同样的效果。图1显示了框架被整合起来时,从最高层次看到的视图。
应用层
许多设计良好的web 应用,可以被按职责分为四层。这些层次是表现层、持久层、业务层、和领域模型层。每一个层次都有其独特的职责,不能把各自的功能与其它层次相混合。每一个应用层都应该和其它层隔离开来,但允许使用接口在层间进行通信。我们开始来看看每个层,并讨论一下它们各自都应该提供什么和不应该提供什么。
表现层
一个典型的web 应用的末端是表现层。许多Java开发者都知道Struts 提供了什么东西。然而,太多时候,耦合代码比如业务逻辑被放进org.apache.struts.Action中。所以,我们先总结一下Struts 之类的框架应该提供什么。下面就是Struts 的职责所在:
l 管理用户的请求和响应
l 提供一个控制起来将调用委托到业务逻辑和其他上游处理
l 将来自于抛出例外的其他层的例外处理到Struts Action 中
l 组装可以在视图中表现的模型对象
l 执行UI 校验
下面是一些经常可以使用Struts进行编码但是不应该和表现层关联的事情:
l 直接和数据库交互,比如JDBC调用
l 与应用相关的业务逻辑和校验
l 事务管理
在表现层中引入这些类型的代码将导致类型耦合和维护负担。
持久层
一个典型Web应用的另一端是持久层。这也是应用中最容易很快失控的地方。开发者通常低估了自己构建自己的持久层框架的挑战。一个定制的,内部开发的持久层不仅需要大量的开发时间,并且通常缺乏功能和难以管理。目前有许多解决这些问题的开源对象关系映射 (ORM) 框架。特别地, Hibernate 框架就允许Java中的对象-关系的持久性和查询服务。Hibernate 对已经熟悉了SQL 和JDBC API 的Java开发者来或具有中度的学习曲线。Hibernate 的持久对象基于POJO和Java 群集(collections)。此外,使用Hibernate 不和你的IDE接口。下面列出了你需要在持久性框架中编写的代码类型:
l 查询关系信息到对象中。Hibernate是通过称为HQL的OO查询语言,或者使用更有表现能力的规则API,来完成这个工作的。除了使用对象而不是表,使用字段而不是列的方式,HQL非常类似于 SQL。也有一些新的特定的HQL 语言特征需要学习;但是,它们是很容易理解和良好编写的。HQL 是一种用于查询对象的自然语言,而对象,只需要很少的学习曲线吧。.
l 存储、更新和删除存储在数据库中的信息
l 高级的对象关系映射框架比如Hibernate支持大部分主流SQL数据库,它们支持父/子关系,事务,继承和多态。
下面是应该在持久层避免的一些事情:
l 业务逻辑应该置于应用的更高层中。这里只允许数据访问方法。
l 不应该使持久逻辑和表现逻辑耦合。避免表现组件如JSP或者基于servlet的类中的逻辑直接和数据访问进行通信。通过将持久性逻辑隔离在其自己的层中,应用将具有更加灵活的修改性而不影响到其他层的代码。例如, Hibernate 可以使用其他持久框架和API代替,而不需要修改其它层中的代码。
业务层
典型的Web应用的中间组件一般是业务层和服务层。从编程的角度来说,service layer经常被忽略。这种类型的代码散布于UI表现层和持久层并不是不多见。这些都不是正确的地方因为它导致了紧密耦合的应用和难以维护的代码。幸运的是,大多数框架都解决了这个问题。这个空间内最流行的两个框架是Spring 和PicoContainer。它们都被视为是具有非常小的足迹(footprint)并且决定如何将你的对象整合在一起的微容器(microcontainer)。这些框架都建立在一种叫做依赖性注入(dependency injection) (也称控制反转(inversion of control:IOC))的简单概念之上。我们将关注Spring中通过针对命名配置参数的bean属性的setter 注入的使用。Spring 也允许一种更加高级的构造器注入(constructor injection)形式作为setter injection 的可选替代。对象通过简单的XML 文件进行连接,该配置文件包含对各种对象的引用,比如事务管理处理器(transaction management handler),对象工厂,包含业务逻辑的服务对象,以及数据访问对象(DAO)。我们随后会用一些例子来澄清Spring中使用这些改变的方式。业务层应该负责下面的问题:
l 处理应用的业务逻辑和业务校验
l 管理事务
l 允许与其他层进行交互的接口
l 管理业务级对象之间的依赖性
l 加入了表现和持久层之间的灵活性,以便它们不需要彼此进行直接通信
l 从表现层暴露上下文给业务层以获得业务服务
l 管理从业务层到表现层的实现
领域模型层
最后,因为我们要解决实际的问题的web应用,我们需要一套在不同的层间移动的对象。领域模型层包含的是表达实际业务对象的对象,比如Order, OrderLineItem, Product 等等。这一层允许能让开发者不再构建和维护不必要的数据传输对象DTO来匹配其领域对象。例如, Hibernate允许你读取数据库信息到一个领域对象的对象图中,以便你可以在离线的情况下将其表现在UI层中。这些对象可以被更新并跨过表现层发送回去,然后进行数据库更新。另外,你不再需要将对象转变成DTO,因为它们在不同的层间移动时可能会丢失事务。这种模型允许Java 开发者能够以OO风格的方式很自然的处理对象,而不用编写额外的代码。
整合一个简单的例子
到 此,应该对各种层次和组件有一个高层的理解了罢。可以开始一些实践了。再次说明。我们的例子整合了Struts, Spring, 和Hibernate 框架。每个框架都包含大量的内容细节,我们不会多述。我们的目的使用一个例子向你说明如何将它们整合在一起构建一个优雅的Web应用架构。实例将演示一个请求是如何得到各层的服务的。此应用的用户可以将一个订单保存在数据库中并且察看数据中的已有订单。进一步的增强允许将用户更新和删除现有订单。
首先,我们将常见我们的领域对象,因为它们是要和各层沟通的。这些对象将允许我们能够定义那些对象需要持久化,那些业务逻辑需要提供,以及应该设计那些表现接口。接下来,我们将使用Hibernate 来为领域对象配置持久层和定义对象关系映射。然后,我们将定义和配置我们的业务层。在完成这些组件后,我们将讨论如何使用Spring将这些层关联起来。最后,我们将提供一个表现层,它知道如何与业务服务层通信以及如何处理来自于其他层的例外。
Appendix B
举例
1.主要说明SSH各部分的作用:
1>Struts,Struts总的来说就是两个字--"动作"
全程通过struts-config.xml进行配置动作,配置表单,配置动作以及转发:主要有ActionForm,Action的书写(Action我建议用Struts的DispathAction,后面在Spring的配置的时候大大减少配置量)和struts-config.xml的配置!
2>hibernate,hibernate总的来说就是三个字--"持久层"
主要负责持久层:通过hibernate.cfg.xml配置数据库的连接,配置javabean的数据库映射xml文件,书写持久层,这里的持久层Manager,通过spring注入的DAO数据库的实现完成一些方法,其中hibernate 的DAO要通过Spring提供的HibernateDaoSupport类,进行方法的实现与数据库的增删改,更新等操作.
3>spring,spring总的来说就是两个字--"管理",管理整个流程,
对事务的管理,对hibernate的管理(创建数据库的连接),对Struts的管理(管理Struts全部的动作),管理hibernate的Manager和Dao(主要是对Manager中的dao进行对象的注入).
2.主要的配置和代码:
1>.总的配置web.xml
web.xml是J2EE web方向的心脏,配置如下:
<web-app>
<!--配置struts-->
<servlet>
<servlet-name>action</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>3</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>3</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<!-- 配置spring-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext-*.xml</param-value>
<!--这里有三个spring的配置文件applicationContext-actions,applicationContext-beans,applicationContext-commons-->
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 这是Spring中的一个编码过滤器-->
<filter>
<filter-name>Spring characterencoding filter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Spring characterencoding filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 这个过滤器是用在一个页面请求时,打来Session,生成完页面生关闭Session,这样就可以解决laze -->
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--spring来对hibernate的应用-->
</web-app>
web.xml主要配置基本的动作转发交给struts-config.xml,Spring的监听器listener:org.springframework.web.filter.CharacterEncodingFilter
,乱码的处理UTF-8,和hibernate的小配置org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.
2>Struts的配置:
Struts-config配置(主要介绍Action的配置,这里的Action为DispathAction)
<action-mappings>
<!--这个进行User的全部操作,一般为这种款式的链接/User.do?Action=login-->
<action path="/User"
type="org.springframework.web.struts.DelegatingActionProxy"
name="UserActionForm"
parameter="Action"
scope="request"
validate="false">
<!-- 登陆转发页面 -->
<forwardname="Login_Success" path="/user/ShowMessage.jsp"/>
<forwardname="Login_Failed" path="/login_f.jsp" />
</action>
Action 由 操作业务层要用到Spring的注入(构造/设置)的Manager,我代码:
XXXAction extemds DispathAction{
private VideoManager videoManager;
//设置注入
public void setVideoManager(VideoManager videoManager) {
this.videoManager = videoManager;
}
//后面就可以直接用videoManager去操作业务层了,
}
//这里为什么能注入videoManager,是因为这里的XXXAction由Spring管理,而Struts的Action只是通过org.springframework.web.struts.DelegatingActionProxy让Spring来管理,当产生这个动作,Spring就set注入videoManager到XXXAction的类中.所以这里videoManager有值!!!
3>hibernate的配置
主要的hibernate.cfg.xml和javabean的映射,DAO的书写问题
hibernate.cfg.xml和javabean的映射没有什么变化(单用hibernate的经验就ok),主要是DAO的实现问题:
这里可以用Spring提供的类HibernateDaoSupport,很好很强大,这样就不必担心事务(Spring会自动处理),而只是写简短的代码,简化操作,这又体现Spring的管理!!!
简短代码展示:
XXXDAOImp extends HibernateDaoSupport implements XXXDAO {
public void AddMusic(MusicTO music) throws Exception {
getHibernateTemplate().save(music);
}
//这就是添加音乐的代码,够简短吧
}
这里的XXXDAOImp也要纳入到Spring的管理之中(见后面的Spring配置,主要对Manager里面的DAO进行注入)
4>Spring的配置
a.applicationContext-actions.xml主要对Struts的动作进行配置(管理全部的Struts动作)
<!-- 对user的全部的Action进行处理,这里用到了DispatchAction,链接形如:NovaMedia/User.do?Action=Login-->
<bean name="/User"class="greatwqs.struts.action.UserAction">
<propertyname="userManager" ref="userManager"></property>
<propertyname="musicManager" ref="musicManager"></property>
</bean>
b.applicationContext-beans.xml主要对hibernate里面的DAO和Manager进行全部的配置(管理hibernate)
<!-- GREATWQS说明:这个只是配置一切的DAO和Manager的配置和联系 -->
<bean id="adminDAO"class="greatwqs.hibernate.dao.imp.AdminDAOImp">
<property name="sessionFactory"ref="sessionFactory"></property>
</bean>
<bean id="adminManager"class="greatwqs.spring.service.imp.AdminManagerImp">
<propertyname="adminDAO" ref="adminDAO"/>
</bean>
<!--配置管理员的DAO和Manager完毕-->
c.applicationContext-commons.xml主要配置(Spring的基本配置)
<beans>
<!--GREATWQS说明:这个配置文件是针对spring的常用的功能进行的配置:sessionFactory,事务,AOP等的配置-->
<!-- 配置SessionFactory -->
<bean id="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<propertyname="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
</bean>
<!-- 配置事务管理 -->
<bean id="TxManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory"ref="sessionFactory"></property>
</bean>
<!-- 配置事务的传播性 -->
<tx:advice id="txAdvice"transaction-manager="TxManager">
<tx:attributes>
<!--propagation="REQUIRED"有事务则直接用,无事务则直接开启-->
<tx:method name="Add*" propagation="REQUIRED"/>
<tx:method name="Delete*" propagation="REQUIRED"/>
<tx:method name="Modify*" propagation="REQUIRED"/>
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 配置那些类的那些方法参与事务 -->
<aop:config>
<aop:pointcutid="pointcut" expression="execution(*greatwqs.hibernate.dao.imp.*.*(..))"/>
<aop:advisoradvice-ref="txAdvice" pointcut-ref="pointcut"/>
<!--这里进行应用上面的配置属性,失误的传播属性等方案-->
</aop:config>
</beans>
3.后面的Ajax思考:
原来写Ajax的代码都是new的对象,再去全部进行的数据库的操作,用了Spring就模糊了,对象不能new了,但是最后还是由Spring的全局管理给我了答案(既然动作都是由Spring管理,我的Ajax的传值也用动作再附加参数,再通过这个动作再进行Spring的注入获得数据库的连接,最后生成jsp的xml文件)成功的利用起了.
也给我一个启示:Spring的管理,管理全局
以前在网上查询的ssh架设,利用Ajax很多都用到了jquery,也很好很强大!!
Appendix C
Spring 3.0配置多个DispatcherServlet的方法及注意事项
http://xieshaohu.wordpress.com/2011/01/20/spring-3-0%E9%85%8D%E7%BD%AE%E5%A4%9A%E4%B8%AAdispatcherservlet%E7%9A%84%E6%96%B9%E6%B3%95%E5%8F%8A%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9/
项目中需要同时用到两个视图解析器,一个报表的,一个jsp的。这就产生了标题所述的需求。通过阅读Spring Framework参考手册以及示例,解决了这个问题,中间也走了不少弯路,碰到了不少问题,特记录下来。
配置多个DispatcherServlet有多种方法,一种是在DispatcherServlet中直接指定此DispatcherServlet对应的配置文件。例如:
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/app-config.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
但是这种配置方法存在一个问题:由于DispatcherServlet对应的Controller需要访问Service并且使用dataSource,而DispatcherServlet之间的上下文是分离的,势必会出现多个dataSource的情况,降低了数据库连接使用的效率。
后来找到了第二种方法,目前正在使用的:DispatcherServlet不指定具体的配置文件,并且DispatcherServlet只初始化自己需要使用到的Controller类,然后由org.springframework.web.context.ContextLoaderListener初始化除Controller以外的全部对象。这样子多个dataSource的问题解决了。配置如下:
web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/*-config.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
由于没有指定名称,所以spring默认会在WEB-INF目录下寻找DispatcherServlet名称开头的-servlet.xml文件,上面这个配置寻找的app-servlet.xml文件。
app-servlet.xml:
<!– 扫描所有的业务Controller,加载json转换服务对象,排除所有的报表Controller–>
<context:component-scan base-package=”com.xieshaohu.**.action” >
<context:include-filter type=”regex”expression=”.*JacksonConversionServiceConfigurer$”/> <context:exclude-filter type=”aspectj”expression=”com.xiehshaohu.project.reports.action.**.*”/></context:component-scan>
<!– 通过@Controller 注解实例化Controller类–>
<mvc:annotation-driven />
<!– JSP视图控制器 –>
<bean id=”jspViewResolver”>
<property name=”viewClass”value=”org.springframework.web.servlet.view.JstlView”/>
<property name=”prefix” value=”/WEB-INF/views/” />
<property name=”suffix” value=”.jsp” />
</bean>
另外还有一个report-servlet.xml配置,web.xml中的内容和app的配置类似。
report-servlet.xml:
<!– 扫描所有的报表Controller对象–>
<context:component-scan base-package=”com.xieshaohu.project.reports.action”/>
<!– Configures the @Controller programming model –>
<mvc:annotation-driven />
<bean id=”viewResolver”class=”org.springframework.web.servlet.view.ResourceBundleViewResolver”> <property name=”basename” value=”views” />
</bean>
然后就是在org.springframework.web.context.ContextLoaderListener初始化的-config.xml配置文件中实例化Service和Dao了。
<!– 扫描Classpath下所有的@Compnents对象,排除Controller和json转换服务对象–>
<context:component-scan base-package=”com.xieshaohu”>
<context:exclude-filter type=”regex” expression=”.*Controller$”/>
<context:exclude-filter type=”regex”expression=”.*JacksonConversionServiceConfigurer$”/></context:component-scan>
通过以上配置,现在就可以实现多个DispatcherServlet了,并且共享了同一个dataSource。在配置的过程中碰到了以下问题。
- @Transactional不生效,导致连接泄露。
按照约定,所有的@Transactional注解都是在@Service中,出现这个问题的原因是,我在app-servlet.xml中初始化了所有的对象,包括@Controller,@Service,@Repository。但是按照官方手册314页正上方的说明,DispatherServlet扫描的对象中使用了@Transactional注解,则只会扫描@Controller中的@Transctional注解。所以出现了连接泄露的问题。所以最后配置成了只在*-servlet.xml中初始化@Controller。
英文原文:
<tx:annotation-driven/> only looks for @Transactional on beans in the same application context it is defined in. This means that, if you put <tx:annotation-driven/> in a WebApplicationContext for a DispatcherServlet, it only checks for @Transactional beans in your controllers, and not your services. - DispatcherServlet间互相访问的问题。
这个问题直接参考Application Context – three ways to get the context的第一种方法解决。实现ApplicationContextAware接口即可。 - Service没有使用接口编程,导致@Controller初始化时提示找不到对应的Service实例。
上面这个问题通过修改程序解决,看来面向接口编程很重要,下面这点更加充分的说明了问题。 - Service实例化时提示无法访问通过@Repository注解声明的Dao
出现这个问题的原因还是因为没有在Service中使用接口引用Dao,导致程序在初始化时就要寻找实例。
Appendix D