阳光男孩

Never give up!

Entries Tagged ‘高质量’

编写高质量Java代码:Ajax单元测试实践

2顶一下 您可能从编写 Ajax 应用程序中获得了极大乐趣,但是对它们执行单元测试却着实让人头痛。   在本文中,Andrew Glover 着手解决 Ajax 的弱点(其中之一),即应对异步 Web 应用程序执行单元测试的固有挑战。   幸运的是,他发现在 Google Web Toolkit 的帮助下,解决这个特殊的代码质量问题要比预想的容易。   Ajax 在近期无疑是 Web 开发界最时髦的字眼之一 ??   与 Ajax 相关的...[阅读全文]

2
顶一下

您可能从编写 Ajax 应用程序中获得了极大乐趣,但是对它们执行单元测试却着实让人头痛。

  在本文中,Andrew Glover 着手解决 Ajax 的弱点(其中之一),即应对异步 Web 应用程序执行单元测试的固有挑战。

  幸运的是,他发现在 Google Web Toolkit 的帮助下,解决这个特殊的代码质量问题要比预想的容易。

  Ajax 在近期无疑是 Web 开发界最时髦的字眼之一 ??

  与 Ajax 相关的工具、框架、书籍以及 Web 站点的剧增就是该技术流行的最好证明。

  此外,Ajax 应用程序也相当灵巧,不是吗?不过,像任何一个开发过 Ajax 应用程序的人证实的一样,对 Ajax 执行测试真的很不方便。事实上,Ajax 的出现已经从根本上使得许多测试框架和工具失效,因为它们并没有针对异步 Web 应用程序测试进行设计!

  有趣的是,某个支持 Ajax 的框架的开发人员注意到了这个限制,并为此做了一些非常新颖的设计:内置的可测试性。除此之外,由于该框架简化了使用 Java? 代码(而不是 JavaScript)创建 Ajax 应用程序,它的起点甚高,并且充分利用了 Java 平台上无可置疑的标准测试框架:JUnit。

  我所论及的框架当然是非常流行的 Google Web Toolkit,也就是 GWT。在本文中,我将向您展示 GWT 如何实际地利用 Java 兼容性,使 Ajax 应用程序的每个部分都能像与之对应的同步应用程序一样进行测试。

  改进代码质量

  别错过 Andrew Glover 的 代码质量讨论论坛,里面有关于代码语法、测试框架以及如何编写专注于质量的代码的帮助。

  JUnit 和 GWTTestCase

  因为与 GWT 有关的 Ajax 应用程序采用 Java 代码编写,所以非常适合开发人员使用 JUnit 进行测试。事实上,GWT 开发小组还为此创建了一个帮助器类 GWTTestCase,扩展自 JUnit 的 3.8.1 TestCase。该基类添加了一些功能,可测试 GWT 代码并处理某些基础实现从而启动并运行 GWT 组件。

  Google Web Toolkit

  Google Web Toolkit 在 Java Web 开发社区的发布声势浩大,同时也获得了与之相称的巨大轰动。GWT 为利用 Java 代码进行设计、构建和部署支持 Ajax 的 Web 应用程序提供了一种新颖的方式。Java Web 开发人员不再需要学习 JavaScript 并花费数个小时解决特定于浏览器的问题,他们可以直接进行与 Ajax 有关的富含信息的动态 Web 应用程序设计。

  需要提醒的是:GWTTestCase 并非用来测试

  与 UI 相关的代码 ?? 它是为了便于测试那些由 UI 交互触发 的异步问题。对 GWTTestCase 用途的误解使许多刚接触 GWT 的开发人员备受挫折,因为他们期望能够用它方便地模拟用户界面,但最终发现这是徒劳的。

  Ajax 组件有两个基本组成:

  体验和功能,这些都被设计成异步方式。

  图 1 演示了一个模拟 Web 表单的简单 Ajax 组件。

  由于该组件支持 Ajax,表单的提交是异步执行的(即:无需重新载入与传统表单提交关联的页面)。

  图 1. 一个支持 Ajax 的简单 Web 表单

  输入一个有效单词,单击组件的 Submit 按钮,将向服务器发送消息请求该单词的定义。

  该定义通过回调异步返回,相应地插入到 Web 页面,如图 2 所示:

  图 2. 单击 Submit 按钮后显示响应

  功能性和集成测试

  图 2 所示的交互测试可用于多个不同场景,

  但是其中两种场景最为常见。从功能性观点考虑,您或许希望编写一个测试:填入表单值,单击 Submit 按钮,然后验证表单是否显示定义。

  另外一个选择是集成测试,使您能够验证客户端代码的异步功能。GWT 的 GWTTestCase 正是

  被设计用来执行此类测试。

  需要牢记的是:在 GWTTestCase 测试用例环境下不可以进行用户界面测试。

  在设计和构建 GWT 应用程序时,您必须清楚不要依赖用户界面 测试代码。

  这种思路需要把交互代码从业务逻辑中分离出来,正如您已经了解的,这是最佳的入门实践!

  举例而言,重新查看图 1 和图 2 所示的 Ajax 应用程序。

  该应用程序由四个逻辑部分构成:TextBox 用于输入目标单词,Button 用于执行单击,还有两个 Label(一个用于 TextBox,另一个显示定义)。

  实际 GWT 模块的初始方法如清单 1 所示,但是您该如何测试这段代码呢?

  清单 1. 一个有效的 GWT 应用程序,但是如何测试它?
1 public class DefaultModule implements EntryPoint {
2
3 public void onModuleLoad() {
4 Button button = new Button(“Submit”);
5 TextBox box = new TextBox();
6 Label output = new Label();
7 Label label = new Label(“Word: “);
8
9 HorizontalPanel inputPanel = new HorizontalPanel();
10 inputPanel.setStyleName(“input-panel”);
11 inputPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
12 inputPanel.add(label);
13 inputPanel.add(box);
14
15 button.addClickListener(new ClickListener() {
16 public void onclick(Widget sender) {
17 String word = box.getText();
18 WordServiceAsync instance = WordService.Util.getInstance();
19 try {
20 instance.getDefinition(word, new AsyncCallback() {
21
22 public void onFailure(Throwable error) {
23 Window.alert(“Error occurred:” + error.toString());
24 }
25
26 public void onSuccess(Object retValue) {
27 output.setText(retValue.toString());
28 }
29 });
30 }catch(Exception e) {
31 e.printStackTrace();
32 }
33 }
34 });
35
36 inputPanel.add(button);
37 inputPanel.setCellVerticalAlignment(button,
38 HasVerticalAlignment.ALIGN_BOTTOM);
39
40 RootPanel.get(“slot1″).add(inputPanel);
41 RootPanel.get(“slot2″).add(output);
42 }
43 }

  清单 1 的代码在运行时发生了严重的错误:它无法按照 JUnit 和 GWT 的 GWTTestCase 进行测试。

  事实上,如果我试着为这段代码编写测试,从技术方面来说它可以运行,但是无法按照逻辑工作。考虑一下:您如何对这段代码进行验证?惟一可用于测试的 public 方法返回的是 void,那么,您怎么能够验证其功能的正确性呢?

  如果我想以白盒方式验证这段代码,就必须分离业务逻辑和特定于用户界面的代码,这就需要进行重构。这本质上意味着把清单 1 中的代码分离到一个便于测试的独立方法中。

  但是这并非听上去那么简单。很明显组件挂钩是通过 onModuleLoad() 方法实现,但是如果我想强制其行为,可能 必须操纵某些用户界面(UI)组件。

  分解业务逻辑和 UI 代码

  第一步是为每个 UI 组件创建访问器方法,

  如清单 2 所示。按照该方式,我可以在需要时获取它们。

  清单 2. 向 UI 组件添加访问器方法使其可用
1 public class WordModule implements EntryPoint {
2
3 private Label label;
4 private Button button;
5 private TextBox textBox;
6 private Label outputLabel;
7
8 protected Button getButton() {
9 if (this.button == null) {
10 this.button = new Button(“Submit”);
11 }
12 return this.button;
13 }
14
15 protected Label getLabel() {
16 if (this.label == null) {
17 this.label = new Label(“Word: “);
18 }
19 return this.label;
20 }
21
22 protected Label getOutputLabel() {
23 if (this.outputLabel == null) {
24 this.outputLabel = new Label();
25 }
26 return this.outputLabel;
27 }
28
29 protected TextBox getTextBox() {
30 if (this.textBox == null) {
31 this.textBox = new TextBox();
32 this.textBox.setVisibleLength(20);
33 }
34 return this.textBox;
35 }
36 }

  现在我实现了对所有与 UI 相关的组件的编程式访问(假设所有需要进行访问的类都在同一个包内)。以后我可能需要使用其中一种访问进行验证。我现在希望限制 使用访问器,如我已经指出的,这是因为

  GWT 并非设计用来进行交互测试。所以,我不是真的要试图测试某个按钮实例是否被单击,

  而是要测试 GWT 模块是否会对给定的单词调用服务器端代码,并且服务器端会返回一个有效定义。方法为将 onModuleLoad() 方法的定义获取逻辑推入(不是故意用双关语!)一个可测试方法中,如清单 3 所示:

  清单 3. 重构的 onModuleLoad 方法委托给更易于测试的方法
1 public void onModuleLoad() {
2 HorizontalPanel inputPanel = new HorizontalPanel();
3 inputPanel.setStyleName(“disco-input-panel”);
4 inputPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
5
6 Label lbl = this.getLabel();
7 inputPanel.add(lbl);
8
9 TextBox txBox = this.getTextBox();
10 inputPanel.add(txBox);
11
12 Button btn = this.getButton();
13
14 btn.addClickListener(new ClickListener() {
15 public void onClick(Widget sender) {
16 submitWord();
17 }
18 });
19
20 inputPanel.add(btn);
21 inputPanel.setCellVerticalAlignment(btn,
22 HasVerticalAlignment.ALIGN_BOTTOM);
23
24 if(RootPanel.get(“input-container”) != null) {
25 RootPanel.get(“input-container”).add(inputPanel);
26 }
27
28 Label output = this.getOutputLabel();
29 if(RootPanel.get(“output-container”) != null) {
30 RootPanel.get(“output-container”).add(output);
31 }
32 }

  如清单 3 所示,我已经把 onModuleLoad() 的定义获取逻辑委托给 submitWord 方法,

  如清单 4 定义:

  清单 4. 我的 Ajax 应用程序的实质!
1 protected void submitWord() {
2 String word = this.getTextBox().getText().trim();
3 this.getDefinition(word);
4 }
5
6 protected void getDefinition(String word) {
7 WordServiceAsync instance = WordService.Util.getInstance();
8 try {
9 instance.getDefinition(word, new AsyncCallback() {
10
11 public void onFailure(Throwable error) {
12 Window.alert(“Error occurred:” + error.toString());
13 }
14
15 public void onSuccess(Object retValue) {
16 getOutputLabel().setText(retValue.toString());
17 }
18 });
19 }catch(Exception e) {
20 e.printStackTrace();
21 }
22 }

  submitWord() 方法又委托给 getDefinition() 方法,我可以用 JUnit 测试它。getDefinition() 方法从逻辑上独立于特定于 UI 的代码(对于绝大部分而言),并且可以在没有单击按钮的情况下得到调用。另一方面,与异步应用程序有关的状态问题和 Java 语言的语义规则也规定了我不能在测试中完全 避免与 UI 相关的交互。仔细查看清单 4 中的代码,您能够发现激活异步回调的 getDefinition() 方法操纵了某些 UI 组件 ??

  一个错误警告窗口以及一个 Label 实例。

  我还可以通过获得输出 Label 实例的句柄,断言其文本是否是给定单词的定义,从而验证应用程序的功能。

  在用 GWTTestCase 测试时,最好不要 尝试手工强制改变组件状态,而应该让 GWT 完成这些工作。举例而言,在清单 4 中,我想验证对某个给定单词返回了其正确定义并放入一个输出 Label 中。无需操作 UI 组件来设置这个单词;我只要直接调用 getDefinition 方法,然后断言 Label 具有对应定义。

  既然我已经编写好了计划进行测试的 GWT 应用程序,我需要实际编写测试,这意味着设置 GWT 的 GWTTestCase。

  设置 GWTTestCase

  若想从 GWTTestCase 的测试魔力中获益,需要遵守一些规则。

  幸运的是,规则很简单:

  所有用于实现测试的类和待测 GWT 模块必须位于同一个包内。

  运行测试时,您必须至少传递一个 VM 参数,指明在哪种 GWT 模式(托管或 Web)下运行测试。

  您必须实现 getModuleName() 方法,它返回一个 String,表示您的 XML 模块文件。

  最后,因为与服务器端实体通信的 Ajax 应用程序在本质上是异步的,GWT 还提供了 Timer 类,以便延迟 JUnit,使异步行为在进行相关断言之前全部完成。实现 getModuleName 和 Timer 类

  我已经指出,我的测试集中于 getDefinition() 方法(如 清单 4 所示)。

  您可以从代码看到,测试逻辑非常简单:传入一个单词(比如 pugnacious),然后验证相应的 Label 文本是否得到正确定义。很简单,对吗?但是不要忘记,getDefinition() 方法在 AsyncCallback 对象中具有某种相关的异步性。

  GWTTestCase 类是一个抽象 类,因为它的 getModuleName() 方法就是这么声明的;因此,当您扩展该类时,您需要实现 getModuleName()(除非您是在为框架创建自己的基抽象类)。模块名实际上就是您的 GWT XML 文件所在的包结构的名称去掉文件扩展名。举个例子,在本例中,我有一个名为 WordModule.gwt.xml 的 XML 文件,它位于

  一个目录结构如:com/acme/gwt。相应的,模块的逻辑名称为 com.acme.gwt.WordModule,这会让您想到 Java 平台的普通包模式。

  我已经得到一个模块名,可以开始定义测试用例了,如清单 5 所示:

  清单 5. 您必须实现 getModuleName 方法并提供一个有效的名字
1 import com.google.gwt.junit.client.GWTTestCase;
2 import com.google.gwt.user.client.Timer;
3
4 public class WordModuleTest extends GWTTestCase {
5
6 public String getModuleName() {
7 return “com.acme.gwt.WordModule”;
8 }
9 }

  到目前为止一切良好,但是我还没有执行任何测试!由于我的 Ajax 应用程序使用 AsyncCallback 对象,在通过测试用例调用 getDefinition() 方法时,我必须强迫 JUnit 延迟运行;否则测试将由于没有任何响应而失败。这就要用到 GWT 的 Timer 类。Timer 使我能够重写 getDefinition() 的 run 方法,在 Timer 内完成测试用例逻辑。(测试用例以独立线程运行,有效地阻塞 JUnit 完成整个测试用例)。

  以我的测试为例,我将首先调用 getDefinition() 方法,然后提供一个 Timer 的 run() 方法的实现。run() 方法得到输出 Label 实例的文本并验证是否是正确定义。

  定义了 Timer 实例后,我就需要确定其何时运行,同时强制 JUnit 挂起直至 Timer 实例完成。也许听起来有点复杂,不必担心,因为实践起来非常简易。实际上,清单 6 展示了整个过程:

  清单 6. 使用 GWT 轻松测试
1 public void testDefinitionValue() throws Exception {
2 WordModule module = new WordModule();
3 module.getDefinition(“pugnacious”);
4 Timer timer = new Timer() {
5 public void run() {
6 String value = module.getOutputLabel().getText();
7 String control = “inclined to quarrel or fight readily;…”;
8 assertEquals(“should be ” + control, control, value);
9 finishTest();
10 }
11 };
12 timer.schedule(200);
13 delayTestFinish(500);
14 }

  正如您所见,Timer 的 run() 方法是我真正验证 Ajax 应用程序功能及其应用远程过程调用的地方。

  请注意 run 方法的最后一步是调用 finishTest() 方法,它意味着一切如预期运行,JUnit 可以不受阻塞正常运行。在实践中,您可能会发现需要根据异步行为完成所需的时间调整延迟时间。

  但用 JUnit 测试 GWT 应用程序的要点在于:您能够在无需 部署完整功能的 Web 应用程序的情况下测试它。因此,您能够更早地 并且更 频繁地 测试您的 GWT 应用程序。

  运行 GWT 测试

  使用 GWT 进行功能测试

  像本文演示的这类简单 Ajax 应用程序可以 从功能角度进行验证,使用包括 Selenium 在内的框架,它会驱动浏览器模拟实际用户行为。不过,要想用 Selenium 运行功能测试,您必须部署完整功能的 Web 应用程序。

  前面我曾提到,如果您想实际运行您的 GWT JUnit 测试,您必须执行大量琐碎的工作来配置运行环境。比如说,要想通过 Ant 的 junit 任务运行我的测试,我就必须确保某些文件位于类路径中并向低层 JVM 提供一个参数。特别是,在调用 junit 任务时,我还要确保托管源文件(以及测试)的目录(或多个目录)位于类路径中,还要告诉 GWT 以何种模式运行。

  我倾向于使用 hosted 模式,这意味着要使用 www-test 标志,如清单 7 所示:

  清单 7. 用 Ant 运行 GWT 测试
1
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

  运行 GWT 测试现在转变成调用问题了。还需注意的是 GWT 测试属于轻量级测试,所以我可以频繁运行测试,甚至是连续运行,就像我在一个持续集成环境(Continuous Integration)中一样。

  结束语

  在本文所示的 GWT 测试用例中,您已经看到用于验证 Ajax 应用程序所需的基本步骤。

  您可以继续测试我的示例 GWT 应用程序,比如测试一些边界用例,但是我认为重点在于:如果使用包含测试特性的框架编写 Ajax 应用程序,测试要比想象中容易。

  要对 GWT 应用程序进行良好测试(对绝大多数应用程序也适用),关键在于设计应用程序时要把测试一并考虑。还要注意 GWTTestCase 不是被用来进行交互测试的。

  您不能使用 GWTTestCase 直接模拟用户。不过您能够以一种间接的方式用它来验证用户交互,正如本文中演示的那样。

原文链接:http://www.88doc.com/node/967

Comments (12)

初学者如何开发出高质量J2EE系统

1顶一下J2EE学习者越来越多,J2EE本身技术不断在发展,涌现出各种概念,本文章试图从一种容易理解的角度对这些概念向初学者进行解释,以便掌握学习 J2EE学习方向。 首先我们需要知道Java和J2EE是两个不同概念,Java不只是指一种语言,已经代表与微软不同的另外一个巨大阵营,所以Java有时是指一种软件系统的流派,当然目前主要是.NET和Java两大主流体系。 J2EE可以说指Java在数据库信息系统上实现...[阅读全文]

1
顶一下

J2EE学习者越来越多,J2EE本身技术不断在发展,涌现出各种概念,本文章试图从一种容易理解的角度对这些概念向初学者进行解释,以便掌握学习 J2EE学习方向。

首先我们需要知道Java和J2EE是两个不同概念,Java不只是指一种语言,已经代表与微软不同的另外一个巨大阵营,所以Java有时是指一种软件系统的流派,当然目前主要是.NET和Java两大主流体系。

J2EE可以说指Java在数据库信息系统上实现,数据库信息系统从早期的dBase、到Delphi/VB等C/S结构,发展到B /S(Browser浏览器/Server服务器)结构,而J2EE主要是指B/S结构的实现。

J2EE又是一种框架和标准,框架类似API、库的概念,但是要超出它们。如果需要详细了解框架,可先从设计模式开始学习。

J2EE是一个虚的大的概念,J2EE标准主要有三种子技术标准:WEB技术、EJB技术和JMS,谈到J2EE应该说最终要落实到这三个子概念上。

这三种技术的每个技术在应用时都涉及两个部分:容器部分和应用部分,Web容器也是指Jsp/Servlet容器,你如果要开发一个Web应用,无论是编译或运行,都必须要有Jsp/Servlet库或API支持(除了JDK/J2SE以外)。

Web技术中除了Jsp/Servlet技术外,还需要JavaBeans或Java Class实现一些功能或者包装携带数据,所以Web技术最初裸体简称为Jsp/Servlet+JavaBeans系统。

谈到JavaBeans技术,就涉及到组件构件技术(component),这是Java的核心基础部分,很多软件设计概念(设计模式)都是通过 JavaBeans实现的。

JavaBeans不属于J2EE概念范畴中,如果一个JavaBeans对象被Web技术(也就是Jsp/Servlet)调用,那么 JavaBeans就运行在J2EE的Web容器中;如果它被EJB调用,它就运行在EJB容器中。

EJB(企业JavaBeans)是普通JavaBeans的一种提升和规范,因为企业信息系统开发中需要一个可伸缩的性能和事务、安全机制,这样能保证企业系统平滑发展,而不是发展到一种规模重新更换一套软件系统。

至此,JavaBeans组件发展到EJB后,并不是说以前的那种JavaBeans形式就消失了,这就自然形成了两种JavaBeans技术:EJB 和POJO,POJO完全不同于EJB概念,指的是普通JavaBeans,而且这个JavaBeans不依附某种框架,或者干脆可以说:这个 JavaBeans是你为这个应用程序单独开发创建的。

J2EE应用系统开发工具有很多:如JBuilder、Eclipse等,这些IDE首先是Java开发工具,也就是说,它们首要基本功能是可以开发出JavaBeans或Java class,但是如果要开发出J2EE系统,就要落实到要么是Web技术或EJB技术,那么就有可能要一些专门模块功能(如eclipse需要 lomboz插件),最重要的是,因为J2EE系统区分为容器和应用两个部分,所以,在任何开发工具中开发J2EE都需要指定J2EE容器。

J2EE容器分为WEB容器和EJB容器,Tomcat/Resin是Web容器;JBoss是EJB容器+Web容器等,其中Web容器直接使用 Tomcat实现的。所以你开发的Web应用程序可以在上面两种容器运行,而你开发的Web+EJB应用则只可以在JBoss服务器上运行,商业产品 Websphere/Weblogic等和JBoss属于同一种性质。

J2EE容器也称为J2EE服务器,大部分时它们概念是一致的。

如果你的J2EE应用系统的数据库连接是通过JNDI获得,也就是说是从容器中获得,那么你的J2EE应用系统基本与数据库无关,如果你在你的 J2EE 应用系统耦合了数据库JDBC驱动的配置,那么你的J2EE应用系统就有数据库概念色彩,作为一个成熟需要推广的J2EE应用系统,不推荐和具体数据库耦合,当然这其中如何保证J2EE应用系统运行性能又是体现你的设计水平了。

衡量J2EE应用系统设计开发水平高低的标准就是:解耦性;你的应用系统各个功能是否能够彻底脱离?是否不相互依赖,也只有这样,才能体现可维护性、可拓展性的软件设计目标。

为了达到这个目的,诞生各种框架概念,J2EE框架标准将一个系统划分为WEB和EJB主要部分,当然我们有时不是以这个具体技术区分,而是从设计上抽象为表现层、服务层和持久层,这三个层次从一个高度将J2EE分离开来,实现解耦目的。

因此,我们实际编程中,也要将自己的功能向这三个层次上靠,做到大方向清楚,泾渭分明,但是没有技术上约束限制要做到这点是很不容易的,因此我们还是必须借助J2EE具体技术来实现,这时,你可以使用EJB规范实现服务层和持久层,Web技术实现表现层;

EJB为什么能将服务层从Jsp/Servlet手中分离出来,因为它对JavaBeans编码有强制的约束,现在有一种对JavaBeans弱约束,使用Ioc模式实现的(当然EJB 3.0也采取这种方式),在Ioc模式诞生前,一般都是通过工厂模式来对JavaBeans约束,形成一个服务层,这也是是Jive这样开源论坛设计原理之一。

由此,将服务层从表现层中分离出来目前有两种可选架构选择:管理普通JavaBeans(POJO)框架(如Spring、 JdonFramework)以及管理EJB的EJB框架,因为EJB不只是框架,还是标准,而标准可以扩展发展,所以,这两种区别将来是可能模糊,被纳入同一个标准了。 但是,个人认为:标准制定是为某个目的服务的,总要牺牲一些换取另外一些,所以,这两种架构会长时间并存。

这两种架构分歧也曾经诞生一个新名词:完全POJO的系统也称为轻量级系统(lightweight),其实这个名词本身就没有一个严格定义,更多是一个吸引人的招牌,轻量是指容易学习容易使用吗?按照这个定义,其实轻量Spring等系统并不容易学习;而且EJB 3.0(依然叫EJB)以后的系统是否可称为轻量级了呢?

前面谈了服务层框架,使用服务层框架可以将JavaBeans从 Jsp/Servlet中分离出来,而使用表现层框架则可以将Jsp中剩余的JavaBeans完全分离,这部分JavaBeans主要负责显示相关,一般是通过标签库(taglib)实现,不同框架有不同自己的标签库,Struts是应用比较广泛的一种表现层框架。

这样,表现层和服务层的分离是通过两种框架达到目的,剩余的就是持久层框架了,通过持久层的框架将数据库存储从服务层中分离出来是其目的,持久层框架有两种方向:直接自己编写JDBC等SQL语句(如iBatis);使用O/R Mapping技术实现的Hibernate和JDO技术;当然还有EJB中的实体Bean技术。

持久层框架目前呈现百花齐放,各有优缺点的现状,所以正如表现层框架一样,目前没有一个框架被指定为标准框架,当然,表现层框架现在又出来了一个 JSF,它代表的页面组件概念是一个新的发展方向,但是复杂的实现让人有些忘而却步。

在所有这些J2EE技术中,虽然SUN公司发挥了很大的作用,不过总体来说:网络上有这样一个评价:SUN的理论天下无敌;SUN的产品用起来撞墙;对于初学者,特别是那些试图通过或已经通过SUN认证的初学者,赶快摆脱SUN的阴影,立即开溜,使用开源领域的产品来实现自己的应用系统。

最后,你的J2EE应用系统如果采取上面提到的表现层、服务层和持久层的框架实现,基本你也可以在无需深刻掌握设计模式的情况下开发出一个高质量的应用系统了。

还要注意的是: 开发出一个高质量的J2EE系统还需要正确的业务需求理解,那么域建模提供了一种比较切实可行的正确理解业务需求的方法,相关详细知识可从UML角度结合理解。

当然,如果你想设计自己的行业框架,那么第一步从设计模式开始吧,因为设计模式提供你一个实现JavaBeans或类之间解耦参考实现方法,当你学会了系统基本单元JavaBean或类之间解耦时,那么系统模块之间的解耦你就可能掌握,进而你就可以实现行业框架的提炼了,这又是另外一个发展方向了。

以上理念可以总结为一句话:
J2EE开发三件宝: Domain Model(域建模)、patterns(模式)和framework(框架)。

推荐一套高质量的J2EE开源系统: JPestore

Comments (216)