站内搜索: 请输入搜索关键词
当前页面: 在线文档首页 > J2EE Tutorial 中文版

第2章动手做一个EJB - J2EE Tutorial 中文版


第2章动手做一个EJB

Dale Green著

Iceshape Zeng译

本章一个简单的客户端/服务器应用程序为例子描述了J2EE应用的开发、部署和运行的整个过程。这个例子由三部分组成:一个货币对换企业Bean,一个J2EE应用程序客户端和一个JSP页面组成的Web客户端。

本章内容:

准备工作

获得例子代码

获得编译工具

启动J2EE服务器

启动deploytool部署工具

创建J2EE应用程序

创建企业Bean

编写企业Bean代码

编译源文件

打包企业Bean

创建J2EE应用程序客户端

编写应用程序客户端代码

打包客户端

指定应用程序客户端的企业Bean引用

创建Web客户端

编写Web客户端代码

编译

打包Web客户端

指定Web客户端的企业Bean引用

设置企业Bean的JNDI名

部署J2EE应用程序

运行J2EE应用程序客户端

运行Web客户端

修改J2EE应用程序

修改类文件

添加文件

更改部署设置

常见问题和解决方法

无法启动J2EE服务器

编译出错

部署出错

J2EE应用程序客户端运行时错误

Web客户端运行时错误

用检验工具检查问题

比较你的EAR文件和样本EAR文件

其它异常

一.准备工作

在你部署例子应用程序之前请先阅读本节。本节介绍我们使用的工具和如何使用它们。

获得例子代码

本章例子的源文件在j2eetutorial/examples/src/ejb/converter目录下,是你解压缩本指南的目标目录的相对路径。

获得编译工具

要编译例子程序的源文件,你需要安装J2EE SDK和ant(它是一个轻便的编译工具)。详细信息请参考前言的编译和运行例子一节。

检查环境变量

J2EE和ant的安装说明解释了怎么设置需要的环境变量。确定这些环境变量的设置成了下表中描述的值:

表2-1 环境变量设置

环境变量

JAVA_HOME

J2SE SDK的安装目录

J2EE_HOME

J2EE SDK的安装目录

ANT_HOME

ANT的安装目录(或解压缩目录)

PATH

包括上面三个工具的安装目录的bin子目录

启动J2EE服务器

在终端窗口中执行如下命令启动J2EE服务器:

j2ee -verbose

虽然verbose不是必需的,但是它对调试很有用。

停止服务器用如下命令:

j2ee -stop

启动deploytool部署工具

deploytool部署工具有两种运行模式:命令模式和GUI图形用户接口模式。本章介绍的是指GUI模式。在终端窗口中执行下面的命令启动deploytool的GUI模式:

deploytool

要查看部署工具的上下文帮助,按F1键。

二.创建J2EE应用程序

在建立例子应用程序的三个组成部分前,你需要创建一个J2EE应用程序,命名为ConverterApp,指定保存应用程序的EAR文件名为ConverterApp.ear。

1.在deploytool部署工具中,选择菜单File\New\Appliction新建应用程序

2. 再出现的对话框中点击Browse

3.在选择文件对话框中定位到路径:j2eetutorial/examples/src/ejb/converter

4.在File Name域中输入ConverterApp.ear

5.点击New Application按钮

6.点击OK

三.创建企业Bean

企业Bean是包含应用程序商业逻辑的服务器端组件。运行时,客户端调用企业Bean的方法来处理商业逻辑。本例的企业Bean是一个叫做ConverterEJB的无状态会话Bean,(企业Bean的分类将在下一章讨论。)它的源文件放在j2eetutorial/examples/src/ejb/converter目录下。

编写企业Bean代码

本例的企业Bean需要以下三类代码:

☆ Remote接口

☆ Home接口

☆ 企业Bean类

编写Remote接口

Remote接口定义客户端可以访问的商业方法。这些商业方法都在企业Bean类里实现。本例的Remote接口Coverter的代码:

import javax.ejb.EJBObject;

import java.rmi.RemoteException;

import java.math.*;

public interface Converter extends EJBObject {

   public BigDecimal dollarToYen(BigDecimal dollars)

      throws RemoteException;

   public BigDecimal yenToEuro(BigDecimal yen)

      throws RemoteException;

}

编写Home接口

Home接口定义客户端可以调用来创建、查找和删除企业Bean的方法。本例的Home接口ConverterHome只有一个create方法,该方法返回企业Bean的远程接口类型。下面是ConverterHome接口的代码:

import java.io.Serializable;

import java.rmi.RemoteException;

import javax.ejb.CreateException;

import javax.ejb.EJBHome;

public interface ConverterHome extends EJBHome {

   Converter create() throws RemoteException, CreateException;

}

编写企业Bean类

本例的企业Bean类是ConverterBean类。它实现了Remote接口Converter定义的两个商业方法:dollarToYen和yenToEuro。ConverterBean的代码如下:

import java.rmi.RemoteException;

import javax.ejb.SessionBean;

import javax.ejb.SessionContext;

import java.math.*;

public class ConverterBean implements SessionBean {

  BigDecimal yenRate = new BigDecimal("121.6000");

   BigDecimal euroRate = new BigDecimal("0.0077");

  public BigDecimal dollarToYen(BigDecimal dollars) {

      BigDecimal result = dollars.multiply(yenRate);

      return result.setScale(2,BigDecimal.ROUND_UP);

   }

  public BigDecimal yenToEuro(BigDecimal yen) {

      BigDecimal result = yen.multiply(euroRate);

      return result.setScale(2,BigDecimal.ROUND_UP);

   }

  public ConverterBean() {}

   public void ejbCreate() {}

   public void ejbRemove() {}

   public void ejbActivate() {}

   public void ejbPassivate() {}

   public void setSessionContext(SessionContext sc) {}

}

编译源文件

现在你可以编译Remote接口(Converter.java)、Home接口(ConverterHome.java)和企业Bean类的源文件了。

1.在终端窗口中进入j2eetutorial/examples directory目录

2.执行命令:ant converter

这个命令编译本例企业Bean和J2EE应用程序客户端的源文件,编译后的类文件放在j2eetutorial/examples/build/ejb/converter目录下(不是src目录)。关于编译的更多信息参考前言部分的编译和运行例子。

注意:在前述ant编译源文件时,它将j2ee.jar文件加在每个编译任务的classpath中。j2ee.jar文件存放在J2EE SDK安装目录的lib子目录下。如果你使用其它工具来编译这些源文件,需要把j2ee.jar文件加入classpath。或者可以直接将该文件加入操作系统的classpath环境变量中。

打包企业Bean

我们使用deploytool部署工具的新建企业Bean向导来打包企业Bean。在这个过程中向导完成如下工作:

1.创建企业Bean的部署描述符文件

2.将部署描述符文件和企业Bean的类文件打包进同一个EJB JAR文件

3.把生成的EJB JAR文件加入应用程序的ConverterApp.ear文件

打包成功后你可以用Tools\Descriptor Viewer菜单查看部署描述符文件内容

用File\New\Enterprise Bean菜单打开新建企业Bean向导,该向导包含以下对话框:

1.Introduction对话框

a) 阅读该向导的说明

b) 点击Next

2.EJB JAR对话框

a) 选择Create New JAR File In Application单选按钮

b) 在下拉框中选择ConverterApp

c) 在JAR Display Name域输入ConverterJAR

d) 点击Edite按钮

e) 在Available Files下的树中定位到j2eetutorial/examples/build/ejb/converter目录。(如果converter目录在树中的层次太深,你可以通过在Starting Directory域中输入converter的整个或者部分路径来简化在树中的目录展开动作)

f) 在Available Files树中选中converter目录下的Converter.class、ConverterBean.class和ConverterHome.class文件点击Add按钮。(你也可以使用鼠标拖放操作来将这些文件加入Contents文本域)

g) 点击OK

h) 点击Next

3.General对话框

a) 在Bean Type下选中Session单选按钮

b) 选中Stateless单选按钮

c) 在Enterprise Bean Class下拉框中选择ConverterBean

d) 在Enterprise Bean Name域输入ConverterEJB

e) 在Remote Home Interface下拉框中选择ConverterHome

f) 在Remote Interface下拉框中选择Converter

g) 点击Next

4.Transaction Management对话框

a) 后面的步骤对本例并不重要,点击Finish完成向导

四.创建J2EE应用程序客户端

J2EE应用程序客户端是用Java语言编写的应用程序。在运行时,客户端应用程序可以运行在和J2EE服务器不同的Java虚拟机中。

本例的J2EE应用程序客户端需要两个不同的JAR文件。第一个JAR文件存放J2EE客户端组件,它包含客户端的部署描述符和类文件。当你使用新建应用程序客户端向导创建该JAR文件时,deploytool会自动将生成的JAR文件加入应用程序的EAR文件中。因为在J2EE规范中被定义,这个JAR文件可以轻易适应不同的J2EE服务器。

第二个JAR文件包含客户端运行时需要的一些存根类文件。这些存根文件使客户端可以访问运行在J2EE服务器上的企业Bean。因为J2EE规范没有定义这个存根JAR文件,它的实现根据服务器的不同而不同,本例中的这个JAR文件只适用于J2EE SDK。

本例的J2EE应用程序客户端源文件为:j2eetutorial/examples/src/ejb/converter/ConverterClient.java。它已经在创建企业Bean一节中被编译过。

编写J2EE应用程序客户端代码

ConverterClient.java源文件展示了企业Bean客户端要完成的基本任务:

☆ 查找Home接口

☆ 创建一个企业Bean实例

☆ 调用商业方法

查找Home接口

ConverterHome接口定义了像create等的企业Bean生命周期方法。在ConverterClient能调用create方法之前,它必须先查找到一个ConverterHome类型的实例对象。以下是查找过程:

1.创建一个初始命名上下文(initial naming context)对象:

Context initial = new InitialContext();

Context接口是Java命名和目录接口(Java Naming and Directory Interface ,JNDI)的一部分。一个命名上下文是一个名字到对象绑定的集合,上下文中已绑定的名字是对象的JNDI名。

一个InitialContext(该类实现Context接口)对象提供名字方案的访问入口。所有的命名操作都关联一个上下文。

2.获得客户端的环境命名上下文对象:

Context myEnv = (Context)initial.lookup("java:comp/env");

Java:comp/env是绑定到ConverterClient组件环境命名上下文对象的名字。

3.获得绑定到名字ejb/simpleConverter的对象

Object objref = myEnv.lookup("ejb/SimpleConverter");

名字ejb/SimpleConverter绑定到一个企业Bean的引用,该引用是企业Bean的Home接口的逻辑名。这样名字ejb/SimpleConverter就等于引用一个ConverterHome对象。企业Bean的名字应该存放在java:com/env/ejb的字上下文中。

4.将得到的引用造型为ConverterHome类型的对象

ConverterHome home =

(ConverterHome)PortableRemoteObject.narrow(objref,ConverterHome.class);

创建一个企业Bean实例

可端调用ConverterHome类型的对象的create方法来创建一个企业Bean实例,该方法返回一个Converter(本例企业Bean的远程接口)类型的对象。Converter接口定义了客户端可调用的企业Bean商业方法。当客户端调用上述的create方法,容器实例化一个企业Bean然后调用ConverterBean.ejbCreate方法。客户端调用代码如下:

Converter currencyConverter = home.create();

调用商业方法

调用商业方法十分简单,就是调用上面获得的Converter类型对象的方法(该接口中定义的方法都是商业方法)。EJB容器会调用运行在服务器中的ConverterEJB实例的对应方法。客户端调用dollarToYen商业方法的代码如下:

BigDecimal param = new BigDecimal ("100.00");

BigDecimal amount = currencyConverter.dollarToYen(param);

下面是客户端ConverterClient的完整代码:

import javax.naming.Context;

import javax.naming.InitialContext;

import javax.rmi.PortableRemoteObject;

import java.math.BigDecimal;

public class ConverterClient {

  public static void main(String[] args) {

     try {

         Context initial = new InitialContext();

         Object objref = initial.lookup ("java:comp/env/ejb/SimpleConverter");

         ConverterHome home = (ConverterHome)PortableRemoteObject.narrow(objref, ConverterHome.class);

         Converter currencyConverter = home.create();

         BigDecimal param = new BigDecimal ("100.00");

         BigDecimal amount = currencyConverter.dollarToYen(param);

         System.out.println(amount);

         amount = currencyConverter.yenToEuro(param);

         System.out.println(amount);

         System.exit(0);

     } catch (Exception ex) {

         System.err.println("Caught an unexpected exception!");

         ex.printStackTrace();

      }

   }

}

打包J2EE应用程序客户端

☆ 客户端的源文件已经在创建企业Bean时同时被编译过了,这里直接打包。

☆ 运行deploytool部署工具的新建应用程序客户端向导,该向导完成如下工作:

☆ 创建应用程序客户端的部署描述符文件

☆ 将部署描述符文件加入客户端的JAR文件

☆ 将生成的JAR文件加入ConverterApp.ear文件

之后你可以通过Tools\Descrptor Viewer菜单查看部署描述符文件内容。

从File\New\Application Client菜单打开该向导,它有以下对话框:

1.Introduction对话框

a) 阅读向导说明

b) 然后Next

2.JAR File Contents对话框

a) 在下拉框中选择ConverterApp

b) 点击Edit按钮

c) 将j2eetutorial/examples/build/ejb/converter/ConverterClient.class文件加入Contents Of树中

d) 确定然后Next

3.General对话框

a) 在Main Class下拉框中选择ConverterClient

b) 确定Display Name域中输入了ConverterClient

c) 在Callback Handler Class下拉框中选择Use container-managed authentication

d) Next后点击Finish完成

指定应用程序客户端的企业Bean引用

当客户端ConverterClient调用lookup方法,它传递企业Bean的Home接口的引用绑定名字给方法:

Object objref = myEnv.lookup("ejb/SimpleConverter");

设置该引用名字的步骤如下:

1.在deploytool工具左边的树视图中选择ConverterClient节点

2.选择右边的EJB Refs选项页

3.点击Add按钮

4.在Coded Name列输入ejb/SimpleConverter

5.在Type列选择Session

6.在Interfaces列选择Remote

7.在Home Interface列输入ConverterHome

8.在Local/Remote Interface列输入Converter

五.创建Web客户端

Web客户端包含在JSP文件j2eetutorial/examples/src/ejb/converter/index.jsp中。JSP文件是一个基于文本的文档,它有两种类型的内容组成:静态模板数据,它们可以是像HTML、WML和XML等等的任意基于文本格式的表示;JSP元素,它是动态内容。

编写Web客户端代码

下面代码的粗体部分和应用程序客户端的工作相似,它查找企业Bean的Home接口,创建企业Bean实例,然后调用商业方法。仅有的不同是lookup调用时的参数,为什么这么用在下一节介绍。

客户端需要的类都在JSP命令(<%@ %>中包括的代码)中导入(import)。因为查找查找Home接口和创建企业Bean实例只执行一次,所以这些代码放在JSP声明(<%! %>中包括的代码)中,声明中的代码将在JSP的初始化方法jspInit中被执行。接着用HTML标记创建包含一个输入框的表单。接着的scriptlet(<% %>中包含的部分)代码从request内值对象中读出参数并将它转换为BigDecimal对象,最后JSP表达式(<%= %>中包含的表达式)调用企业Bean的商业方法并将结果写入送到客户端(浏览器)的页面输出流传。

<%@ page import="Converter,ConverterHome,javax.ejb.*,

javax.naming.*, javax.rmi.PortableRemoteObject,

java.rmi.RemoteException" %>

<%!

   private Converter converter = null;

   public void jspInit() {

      try {

         InitialContext ic = new InitialContext();

         Object objRef = ic.lookup("

            java:comp/env/ejb/TheConverter");

         ConverterHome home =

         (ConverterHome)PortableRemoteObject.narrow(

         objRef, ConverterHome.class);

         converter = home.create();

      } catch (RemoteException ex) {

         ...

      }

   }

   ...

%>

<html>

<head>

    <title>Converter</title>

</head>

<body bgcolor="white">

<h1><center>Converter</center></h1>

<hr>

<p>Enter an amount to convert:</p>

<form method="get">

<input type="text" name="amount" size="25">

<br>

<p>

<input type="submit" value="Submit">

<input type="reset" value="Reset">

</form>

<%

   String amount = request.getParameter("amount");

   if ( amount != null && amount.length() > 0 ) {

      BigDecimal d = new BigDecimal (amount);

%>

   <p><%= amount %> dollars are 

      <%= converter.dollarToYen(d) %>  Yen.

   <p><%= amount %> Yen are

      <%= converter.yenToEuro(d) %>  Euro.

<%

    }

%>

</body>

</html>

编译Web客户端

J2EE服务器自动编译Web客户端的JSP页面,如果是servlet实现,你需要先编译它。

打包Web客户端

运行deploytool工具的新建Web客户端向导,它完成如下工作:

1.创建Web客户端的部署描述符

2.将Web客户端的文件打包进一个WAR文件中

3.将该WAR文件加入应用程序的ConverterApp.ear文件中

可以通过Tools\Descriptor菜单在打包结束后查看部署描述符文件的内容。

用File\New\Web Component菜单打开该向导,它有如下对话框组成:

1.Introduction对话框。阅读向导说明

2.WAR File对话框

a) 选中Create New WAR File In Application

b) 在下拉框中选择ConverterApp

c) 在WAR Display域输入ConverterWAR

d) 点击Edit

e) 将j2eetutorial/examples/build/ejb/converter/index.jsp文件加入Contents Of树中

f) 确定

3.Choose Component Type对话框。选中JSP单选按钮

4.Component General Properties对话框。在JSP Filename下拉框中选择index.jsp。点击Finish完成

指定Web客户端的企业Bean引用

Web客户端的企业Bean的Home接口的引用名为:ejb/TheConverter。Lookup调用:

Object objRef = ic.lookup("java:comp/env/ejb/TheConverter");

设置该引用名步骤如下:

1.在树视图中选择ConverterWAR节点

2.选择EJB Refs选项页

3.点击Add按钮

4.在Coded Name列中输入ejb/TheConverter

5.在Type列选择Session

6.在Interfaces列选择Remote

7.在Home Interface列输入ConverterHome

8.在Local/Remote Interface列输入Converter

六.设置企业Bean的JNDI名

虽然J2EE应用程序客户端和Web客户端访问的是同一个企业Bean,但是它们对企业Bean的Home接口的引用命名不同。J2EE应用程序客户端用ejb/SimpleConverter查找Home接口引用,而Web客户端用ejb/TheConverter。这些引用名都作为lookup调用是的参数。为了让lookup方法能够通过它们找到企业Bean的Home接口类型对象,你必须映射这些引用名到企业Bean的JNDI名。虽然这个映射增减了一个间接访问层,但是它降低了客户端和企业Bean之间的耦合,使J2EE组件更容易装配成应用程序。(这种引用查找在EJB1.1时出现,主要是避免在代码中写死JNDI名来查找企业Bean可能造成的装配时JNDI名冲突)。

以下步骤建立引用名和JNDI名的映射:

1.在树视图中选择ConverterApp节点

2.选择JNDI Name选项页

3.在Application表格中选中ConverterEJB组件,在JNDI Name列中输入MyConverter作为ConverterEJB的JNDI名

4.在References表格中每一行的JNDI Name列中都输入上面的JNDI名

图2-1显示了设置的JNDI名:

图 2-1 ConverterApp JNDI 名选项页

七.部署J2EE应用程序

前面我们已经将本例中的组件全部加入到应用程序中了,现在开始部署。

1.选择ConverterApp应用程序(在树中)

2.选择菜单Tools\Deploy

3.在Introduction对话框中确定Object To Deploy选择的是ConverterApp,Target Server选择的是localhost

4.选中Return Client Jar复选框

5.在Client JAR File Name域中输入j2eetutorial/examples/src/ejb/converter/ConverterAppClient.jar(可以使用Browse按钮),该JAR文件包含可以远程访问ConverterEJB的存根类。下一步

6.在JNDI Names对话框中,检验是不是你前面输入的名字。下一步

7.在WAR Context Root对话框中,为Context Root域输入converter。当你运行Web客户端时,converter将是访问Web的URL的一部分。下一步

8.在Rewiew对话框中点及Finish完成

9.在Deployment Progress对话框部署完成后确定退出部署。

八.运行J2EE应用程序客户端

按以下步骤运行应用程序客户端:

1.在终端窗口中进入j2eetutorial/examples/src/ejb/converter目录

2.确认ConverApp.ear和ConverterAppClient.jar文件在该目录下

3.设置APPCPATH环境变量为ConvertAppClient.jar所在目录

4.执行下面的命令:

runclient -client ConverterApp.ear -name ConverterClient -textauth

5.在出现登录提示时输入用户名:guest。密码:guest123。

6.终端窗口中显示结果如下:

Binding name:'java:comp/env/ejb/SimpleConverter'

12160.00

0.77

Unbinding name:'java:comp/env/ejb/SimpleConverter'

九.运行Web客户端

在浏览器中输入下面的URL访问Web客户端。<host>表示运行J2EE服务器的机器名,如果你的J2EE服务器和访问浏览器在同一机器上,可以用localhost代替作为机器名。

http://<host>:8000/converter

在显示页面的输入框中输入100后点击Submit提交,会看到图2-2所示的结果。

图 2-2 Converter Web客户端

十.修改J2EE应用程序

因为J2EE SDK仅供试验用,所以它支持重复部署。如果你修改了一个J2EE应用程序,你必须重新部署它。

修改类文件

要修改企业Bean的一个类文件,先修改源文件,然后重新编译,最后重新部署应用程序。例如,如果你想修改ConverterBean类的dollarToYen商业方法的汇率,执行如下步骤:

1.编辑ConverterBean.java文件

2.用ant converter命令重新编译ConverterBean.java源文件

3.在deploytool中选择菜单:Tools\Update Files

4.在Update Files对话框中,如果你修改的文件已经列在对话框上面的列表中,点击OK转到第6步。如果列在下面的列表中,它们的修改还没有被发现。选择这些文件中的一个点击Edit Search Paths按钮

5.在Edit Search Paths对话框中指定Update Files对话框查找修改过的文件的路径

a) 在Search Root域中输入查找开始的全路径

b) 在Path Directory列表中,为你想搜索的每一个目录加入一行,不用全路径名,这里的路径都是用对Search Root的相对路径

c) 确定

6.用Tools\Deploy菜单重新部署。在第一步的对话框中确定选中了Save Object Before Deploying复选框。如果你不想马上部署,可以用Tools\Save菜单先保存第5步的设置。

有一种快捷方式来重新部署,就是用菜单Tools\Update And Redeploy。除非文件找不到,否则不会弹出Update Files对话框。

改变WAR文件的内容步骤相同。Update Files操作会检查包括HTML和JSP的任意文件的改动,如果你改动了index.jsp文件,仍然要执行ant converter命令,它会将index.jsp文件从src目录拷贝到build目录。

添加文件

以下步骤可以向EJB JAR或者WAR文件中加入新文件:

1.在deploytool的树视图中选择目标JAR或者WAR文件

2.选择General选项页

3.点击Edit按钮

4.添加需要的文件确定

5.在主窗口中选择菜单:Tools\Update And Redeploy

修改部署设置

要修改ConverterApp的部署设置,先选择特定的选项页然后编辑对应的输入框中内容最后重新部署使修改生效。例如一下步骤将ConverterBean的JNDI名从MyConverter改为ATypo:

1.在deploytool中选中ConverterApp节点

2.选择JNDI Names选项页

3.将两个表中所有JNDI Name列的内容改为Atypo

4.在主窗口中选择File\Save菜单

5.用Tools\Update And Redeploy菜单重新部署

十一常见问题和解决方法

无法启动J2EE服务器

命名和目录服务端口冲突

症状:在你用-verbose参数启动J2EE服务器时,显示如下信息:

J2EE server listen port: 1050

RuntimeException: Could not initialize server...

解决办法:其他应用程序占用了1050端口。停止J2EE服务器,将J2EE SDK安装目录下的config/orb.properies文件里的默认端口1050改为别的端口。默认端口的更多信息清参考J2EE SDK的下载包的配置说明。

Web服务端口冲突

症状:

LifecycleException: HttpConnector[8000].open:

java.net.BindException: Address in use...

解决办法:端口8000被占用,编辑config/web.properties文件更改该端口

不正确的XML解析器

症状:启动J2EE服务器时出现如下错误:

Exception in thread "main"

javax.xml.parsers.FactoryConfigurationError:

org.apache.xerces.jaxp.SAXParserFactoryImpl at ...

解决办法:删除J2SE安装目录下的jre/lib/jaxp.properties文件

编译出错

ant找不到Build文件

症状:执行ant converter命令时,出现如下错误:

Buildfile: build.xml does not exist!

Build failed.

解决办法:在执行ant命令前,进入j2eetutorial/examples./src目录。如果你想在当前目录下执行ant命令,必须在命令里指定Build文件。例如:

ant -buildfile C:\j2eetutorial\examples\src\build.xml converter

编译器不能解析符号

症状:执行ant converter命令时,编译器报告如下错误:

cannot resolve symbol

...

BUILD FAILED

...

Compile failed, messages should have been provided

解决办法:确定你的J2EE_HOME环境变量设置正确(参考本章第一节)

ant1.4在你运行客户端后不编译例子

症状:ant1.4显示如下错误:

The filename, directory name, or volume label syntax is

incorrect.

解决办法:使用ant1.3。1.4版的ant.bat脚本和J2EE SDK的脚本都使用JAVACMD环境变量。例如SDK的runclient.bat脚本设置JAVACMD的值会引起ant.bat执行错误。

部署出错

Classpath里不正确的XML解析器

症状:错误提示如下:

...

[]java.rmi.RemoteException:Error saving/opening

Deployment Error:Bad mapping of key{0}  class{1},

not found: com.sum.enterprise.deployment.xml.ApplicationNode

解决办法:在J2SE安装目录的jre/lib/ext子目录下删除jaxp.jar文件。这个文件里的XML解析器跟J2EE服务器不兼容。如果你没有jaxp.jar文件,或许你的classpath指向Tomcat的XML解析器。这种情况你需要将该路径从classpath环境变量中删除。

Remote Home接口被设置成Local Home接口

症状:错误提示如下:

LocalHomeImpl must be declared abstract.

It does not define javax.ejb.HomeHandle getHomeHandle()

from interface javax.ejb.EJBHome.

解决办法:从EAR文件中将企业Bean删除(Edit\Delete菜单),然后用新建企业Bean向导重新创建该企业Bean。在向导的General对话框中为Remote Home Interface和Remote Interface选择值。

J2EE应用程序客户端运行时错误

客户端抛出NoClassDefFoundError

症状:错误提示如下:

java.lang.NoClassDefFoundError:converter.ConverterHome

解决办法:该错误出现在当客户端找不到ConverterAppClient.jar里的类时。确定你是按照运行J2EE应用程序客户端一节的步骤做的。

客户端找不到ConverterApp.ear

症状:错误提示如下:

IOException: ConverterApp.ear does not exist

解决办法:确定ConverterApp.ear文件存在并且你在命令中用-client参数指示正确:

runclient -client ConverterApp.ear -name ConverterClient

参考创建J2EE应用程序和运行J2EE应用程序客户端两节。

客户端找不到ConverterClient组件

症状:错误提示如下:

No application client descriptors defined for: ...

解决办法:检查你是否已经创建了ConverterClient组件,并确定在runclient命令中用-name参数指定了该组件。

参考打包J2EE应用程序客户端一节。

登录失败

症状:登录时出现如下错误提示:

Incorrect login and/or password

解决办法:确定用户名输入的是:guest。密码输入的是:guest123。

J2EE应用程序还没有部署

症状:客户端提示出错:

NameNotFoundException. Root exception is org.omg.CosNaming...

解决办法:部署应用程序。参考部署J2EE应用程序一节。

JNDI名错误

症状:客户端报告如下错误:

NameNotFoundException. Root exception is org.omg.CosNaming...

解决办法:在ConverterApp的JNDI Names选项页中确定ConverterBean的JNDI名和客户端引用ejb/SimpleConverter引用的JNDI名一致。如果不一致,修改后重新部署。

Web客户端运行时错误

URL中的Web上下文不正确

症状:浏览器报告找不到这个页面(HTTP 404)

解决办法:检查URL里的Web上下文(converter)跟你在Conponent General Properties对话框中指定的一致,它是大小写敏感的。参考打包Web客户端一节。

J2EE应用程序还没有部署

症状:浏览器报告找不到这个页面(HTTP 404)

解决办法:部署

JNDI名错误

症状:当你在Web页中点击Submit提交,浏览器报告如下错误:

A Servlet Exception Has Occurred.

解决办法:在ConverterApp的JNDI Names选项页中确定ConverterBean的JNDI名和Web客户端引用的JNDI名一致。如果不一致,修改后重新部署。

用检验工具检查问题

检验工具(verifier)可以检查部署描述符和方法签名不一致的地方。这些不一致通常导致部署错误或运行时错误。在deploytool里用菜单Tools\Verifier可以启动GUI版的verifer检验工具。你也可以启动单独的GUI版本或者命令行版本。详见附录B。

比较你的EAR文件和样本EAR文件

对大部分例子(包括本章的例子),该指南的下载包里提供了样本J2EE应用程序EAR文件,它们存放在j2eetutorial/examples/ears directory目录下。

其它异常

如果以上的提示都不能解决出现的问题,你可以卸载应用程序,并用cleanup脚本清空J2EE服务器的储藏库。服务器也需要关闭后重新启动:

j2ee -stop

cleanup

j2ee -verbose