|
本文将详细介绍使用 EJB 3.0 技术开发企业应用程序的基础知识,而 EJB 3.0 是 Java EE 5 平台的组成部分。本文还将阐述如何通过 EJB 3.0
技术简化开发企业应用程序的流程。本文使用的是
NetBeans IDE 6.0 发行版。
教程练习
先决条件
本文假定您在以下方面拥有基本知识和编程经验:
教程所需软件
对于本教程,您需要在计算机上安装以下软件:
- "Web & Java EE" 或 "All" 下载版本的
NetBeans IDE 6.0 (下载)
- Java 标准开发工具箱 (JDK) 版本 5.0 或 6.0 (下载)
- GlassFish V2 Application Server (绑定完整的 IDE 下载)或 Sun Java System Application Server 平台版本 9 (下载)
对于本教程,您需要注册 GlassFish/Sun Java System Application Server 及其 IDE 的本地实例。
建立企业应用程序项目
此次练习的目标是创建 NewsApp 企业应用程序项目,其中包含一个 EJB 模块和一个 web 模块。NewsApp 应用程序使用一个消息驱动的 bean 接收和处理 servlet
发送到队列的消息。该应用程序使用 servlets 发送消息给消息驱动的 bean ,以便显示消息。
创建企业应用程序
- 从主菜单中选择 File> New Project (Ctrl-Shift-N)。
- 从 Enterprise 类别中选择 Enterprise Application ,然后单击 Next 按钮。
- 将项目命名为 NewsApp,并将服务器设定为 Sun Java System Application Server。
- 将 Java EE 版本设为 Java EE 5,然后选择 Create EJB Module 和 Create Web Application Module (如果未选中)。
- 单击 Finish 按钮。
小结
在本练习中,我们创建了一个 Java EE 5 企业应用程序,其中包含一个 EJB 模块和一个 web 模块。
编写 EJB 模块
在本练习中,我们将在 EJB 模块中创建对象。我们将创建一个实体类,一个消息驱动 bean 和一个会话外观(Session Facade)。我们还将创建一个持久性单元,以便为容器提供管理实体,和
消息驱动 bean 将使用的 Java 消息服务(Java Message Service ,JMS)资源所需的信息。
创建持久性单元
首先,我们需要创建一个持久性单元,用于定义应用程序中所使用的数据源和实体管理器。
- 右击 EJB 模块,然后选择 New > File/Folder 。
- 从 Persistence 类别中,选择 Persistence Unit ,然后单击 Next 按钮。
- 保持默认的 Persistence Unit 名称。
- 对于 Persistence Provider ,选择
TopLink(默认)。
- 对于Data Source,选择默认数据源
jdbc/sample。
- 检查持久性单元使用了 Java Transaction API,而且 Table Generation Strategy 被设定为 Create ,这
样部署应用程序时就能基于我们的实体类创建表。
- 单击 Finish 按钮。
单击 Finish 时,IDE 将会创建
persistence.xml,并在源代码编辑器中以设计视图打开它。关闭
persistence.xml。
创建
NewsEntity 实体类
在本练习中,我们将创建
NewsEntity 实体类。实体类就是一个简单的 Java 类。创建实体类时,IDE 会添加
@Entity 注释用于将类定义为实体类。创建类之后,我们将在类中创建字段,以表示要在表中保存的数据。
每个实体类都必须有一个主键。创建实体类时,IDE 会添加
@Id 注释用于声明使用哪个字段作为主键。IDE 还会添加
@GeneratedValue 注释,用于指定主 Id 的主要生成策略。
创建
NewsEntity 类的步骤如下:
- 在 Project 窗口在单击鼠标右键 EJB 模块,然后选择 New > File/Folder ,以便打开 New File 向导。
- 从 Persistence 类别中,选择 Entity Class ,然后单击 Next 按钮。
- 键入
NewsEntity 作为类名,键入
ejb 作为包名,让 Primary Key Type 保持为
Long。单击 Finish 按钮。
单击 Finish 时,实体类
NewsEntity.java 就会在源代码编辑器中打开。在源代码编辑器中,完成以下步骤:
- 给类添加以下字段声明:
private String title;
private String body;
- 在源代码编辑器中单击鼠标右键,然后选择 Insert Code ,同时选择 Getter and Setter 为每个字段生成 getter 和 setter 程序。
- 在 Generate Getters and Setters 对话框中,选择
body 和
title 字段,然后单击 Generate 按钮。
- 保存修改。
在下一步中,我们将创建
NewMessage 消息驱动 bean。
创建
NewMessage 消息驱动 Bean
现在,我们将在我们的 EJB 模块中创建
NewMessage 消息驱动。我们将使用 New Message-Driven Bean 向导来创建 bean 和必要的 JMS 资源。
创建
NewMessage 消息驱动 bean 的步骤如下:
- 在 Projects 窗口在单击鼠标右键 EJB 模块,然后选择 New > File/Folder ,可以打开 New File 向导。
- 从 Enterprise 类别中,选择 Message-Driven Beans ,然后单击 Next 按钮。
- 键入
NewMessage 作为类名。
- 从 Package 下拉列表中选择
ejb。
- 单击 Add 打开 Add Message Destination 对话框。
- 在 Add Message Destination 对话框中,键入
jms/NewMessage,然后 选择 Queue 作为目标类型。单击 OK 。
- 确保项目目的地正确,然后单击 Finish 按钮。
单击 Finish 时,新的消息驱动 bean 类
NewMessage.java 就会在源代码编辑器中打开。您可以看到 @MessageDriven 注释和配置属性已经添加到类中。
@MessageDriven(mappedName = "jms/NewMessage", activationConfig = {
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue =
"Auto-acknowledge"),
@ActivationConfigProperty(propertyName = "destinationType", propertyValue =
"javax.jms.Queue")
})
这段注释告诉容器,组件是消息驱动 bean 和 bean 使用的 JMS 资源。当 IDE 生成类时,资源的 Mapped Name (jms/NewMessage) 来自类名 (NewMessage.java)。JMS 资源被映射为 bean 接收消息所在目的地的 JNDI 名称。
New Message-Driven Bean 向导已经把 JMS 资源的信息添加到了
sun-resources.xml中。EJB 3.0 API 支持在 bean 类的 JNDI 命名空间中查找对象,这样我们就不需要配置部署描述符就可以指定 JMS 资源。
EJB 3.0 规范允许我们使用注释直接在一个类中引入资源。现在,我们将使用注释将
MessageDrivenContext 资源引入到我们的类中,然后注入 将被 EntityManager API 使用的
PersistenceContext 资源,以便管理持久性实体实例。我们将在 源代码编辑器中给类添加注释。
- 将
MessageDrivenContext 资源注入到类中,方法是添加以下带注释的字段(以黑体表示)到类中:
public class NewMessage implements MessageListener {
@Resource
private MessageDrivenContext mdc;
- 在类中引入实体管理器,方法是在代码在单击鼠标右键,然后从弹出式菜单中选择 Persistence > Use Entity Manager 。这将在源代码中添加如下注释:
@PersistenceContext
private EntityManager em;
并在代码中生成如下方法:
public void persist(Object object) {
em.persist(object);
}
- 修改
persist 方法,将名称
save。方法应该像如下所示:
public void
save(Object object) {
em.persist(object);
}
- 修改
onMessage 方法,方法是在方法体中加入如下内容:
ObjectMessage msg = null;
try {
if (message instanceof ObjectMessage) {
msg = (ObjectMessage) message;
NewsEntity e = (NewsEntity) msg.getObject();
save(e);
}
} catch (JMSException e) {
e.printStackTrace();
mdc.setRollbackOnly();
} catch (Throwable te) {
te.printStackTrace();
}
- 按下 Alt-Shift-F 组合键,生成所有必需的导入语句。
注意: 生成导入语句时,我们需要
确保导入
jms 和
javax.annotation.Resource 库。
- 保存文件。
创建会话 Bean
接下来,我们将为
NewsEntity 实体类创建会话外观。创建会话外观的步骤如下:
- 右击 EJB 模块,然后选择 New > File/Folder 。
- 从 Persistence 类别中,选择 Session Beans for Entity Classes ,然后单击 Next 按钮。
- 从可用实体类的列表中,选择 ejb.NewsEntity 并单击 Add ,然后单击 Next 按钮。
- 确定将 Package 设置为
ejb 并且已创建本地接口。
- 单击 Finish 按钮。
单击 Finish 按钮后,IDE 将会创建会话外观类
NewsEntityFacade.java,而且该类会在源代码编辑器中打开。IDE 还会创建本地接口
NewsEntityFacadeLocal.java。
EJB 3.0 技术简化了会话 bean 的创建过程,因为它减少了所需代码的数量。您可以看到,注释
@Stateless 用于把类声明为无状态的会话 bean,而类不再需要一条语句来实现
javax.ejb.SessionBean。代码也要清晰很多,因为借助 EJB 3.0 技术,业务方法不再需要代码来声明它们抛出了未经检查的异常。
您可以看到,创建会话外观时,
PersistenceContext 资源被直接注入了会话 bean 组件中。
小结
在本练习中,我们为 EJB 模块中的一个实体类和一个消息驱动编写了代码。我们还创建了我们的应用程序将会使用的 JMS 资源。
编写 Web 模块
现在,我们将在 web 模块中创建 servlets
ListNews 和
PostMessage。这些 servlets 将用于读取和添加消息。
创建
ListNews Servlet
在本练习中,我们将创建一个用于显示数据的简单 servlet。我们将使用注释从我们的 servlet 中调用实体。
- 右击 web 模块项目,然后选择 New > Servlet 。
- 键入
ListNews 作为类名。
- 输入
web 作为包名,然后单击 Finish 按钮。
单击 Finish 按钮后,类
ListNews.java 就会在源代码编辑器中打开。在源代码编辑器中,执行以下步骤:
- 在源代码在单击鼠标右键,然后选择 Enterprise Resources > Call Enterprise Bean 。
- 在 Call Enterprise Bean 对话框中,选择 NewsEntityFacade 然后单击 OK 按钮。单击 OK 按钮后,实体 bean 源代码就会通过使用
@EJB 注释注入到 servlet 中。
- 在
processRequest 方法中,去掉代码的注释,并在方法体中添加以下用黑体表示的行:
out.println("<h1>Servlet ListNews at " + request.getContextPath () + "</h1>");
List news = newsEntityFacade.findAll();
for (Iterator it = news.iterator(); it.hasNext();) {
NewsEntity elem = (NewsEntity) it.next();
out.println(" <b>"+elem.getTitle()+" </b><br />");
out.println(elem.getBody()+"<br /> ");
}
out.println("<a href='PostMessage'>Add new message</a>");
out.println("</body>");
- 按下 Alt-Shift-F 组合键,便可为类生成所有必需的导入语句。生成导入语句时,我们需要
导入
java.util 库。
- 保存对文件所做的修改。
创建
PostMessage Servlet
在本练习中,我们将创建用于发布消息的
PostMessage servlet。我们将使用注释把我们创建的 JMS 资源直接注入到 servlet中,用于指定变量名和它映射到的名称。接着,我们将添加用于发送 JMS
消息的代码,以及用于添加消息的 HTML 窗体的代码。
- 右击 web 模块项目,然后选择 New > Servlet 。
- 键入
PostMessage 作为类名。
- 输入
web 作为包名,然后单击 Finish 按钮。
单击 Finish 按钮后,类
PostMessage.java 就会在源代码编辑器中打开。在源代码编辑器中,完成以下步骤:
- 使用注释把
ConnectionFactory 和
Queue 资源注入,方法是添加如下字段声明(以黑体表示):
public class PostMessage extends HttpServlet {
@Resource(mappedName="jms/NewMessageFactory")
private ConnectionFactory connectionFactory;
@Resource(mappedName="jms/NewMessage")
private Queue queue;
- 现在,我们添加用于发送 JMS 消息的代码,方法是在
processRequest 方法中添加以下用黑体表示的代码:
response.setContentType("text/html;charset=UTF-8");
// Add the following code to send the JMS message
String title=request.getParameter("title");
String body=request.getParameter("body");
if ((title!=null) && (body!=null)) {
try {
Connection connection = connectionFactory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer messageProducer = session.createProducer(queue);
ObjectMessage message = session.createObjectMessage();
// here we create NewsEntity, that will be sent in JMS message
NewsEntity e = new NewsEntity();
e.setTitle(title);
e.setBody(body);
message.setObject(e);
messageProducer.send(message);
messageProducer.close();
connection.close();
response.sendRedirect("ListNews");
} catch (JMSException ex) {
ex.printStackTrace();
}
}
PrintWriter out = response.getWriter();
- 现在,对于用于打印 HTML 和添加消息 web 窗体的代码,我们去掉其注释。在
processRequest 方法中添加如下以黑体表示的代码行:
out.println("Servlet PostMessage at " + request.getContextPath() + "</h1>");
// Add the following code to add the form to the web page
out.println("<form>");
out.println("Title: <input type='text' name='title'><br/>");
out.println("Message: <textarea name='body'></textarea><br/>");
out.println("<input type='submit'><br/>");
out.println("</form>");
out.println("</body>");
- 按下 Alt-Shift-F 可以为类生成所有必需的导入语句。
注意:为
Connection、
ConnectionFactory、
Session 和
Queue 选择要导入的库时,
确保已经导入了
java.jms 库。
- 保存对文件所做的修改。
运行项目
现在,我们可以运行刚才创建的项目。运行项目时,我们想让浏览器打开带有
ListNews servlet 的页面。为此,我们需要在 Enterprise Application 的 Properties 对话框中指定 URL。此 URL
相对于我们应用程序的上下文路径。输入相对 URL 之后,我们就可以从 Projects 窗口中编译、部署和运行我们的应用程序了。
设定相对 URL 和运行我们的应用程序的步骤如下:
- 在 Projects 窗口中,右击 NewsApp enterprise application 节点,然后在弹出菜单中选择 Properties 。
- 在 Categories 窗格中选择 Run 。
- 在 Relative URL 文本框中,键入 /ListNews。
- 单击 OK 按钮。
- 在 Projects 窗口中,右击 NewsApp enterprise application 节点,然后选择 Run Project 。
运行项目时,
ListNews servlet 就会在浏览器中打开,并显示数据库中消息的一个列表。首次运行项目时,数据库是空的,但您可以单击 Add Message 添加一条消息。
使用
PostMessage servlet 添加一条消息时,该消息将被发送给消息驱动 bean,以便写入持久性存储器,而
ListNews servlet 将被调用以显示数据库中的消息。
ListNews 从数据库中获得的消息列表通常还没有包含新消息,因为我们的消息服务是异步的。
故障排除
创建项目时可能会遇到以下一些问题。
JMS 资源的问题
使用向导创建 JMS 资源时,您可能会在输出窗口中看到如下服务器错误消息:
[com.sun.enterprise.connectors.ConnectorRuntimeException:
JMS resource not created : jms/Queue]
这条消息大概是指出,JMS 资源没有创建或没有注册到应用服务器。您可以使用 Sun Java System Application Server 的管理控制台来检查、创建和编辑 JMS 资源。<
/p>
打开管理控制台的步骤如下:
- 在 IDE 的运行时中展开 Servers 节点,确定 Sun Java System Application Server 正在运行。位于 Sun Java System
Application Server 节点旁边的一个小小的绿色箭头指示服务器正在运行中。
- 右击 Sun Java System Application Server 节点,然后选择 View Admin Console ,可以在浏览器中打开登陆窗口。
- 登陆到 Sun Java System Application Server 中。默认的用户名和密码是
admin 和
adminadmin。
- 在浏览器的管理控制台中,展开画面左侧的 Resources 节点 和 JMS Resources 节点。
- 单击画面左侧的 Connection Factories 和 Destination Resources 链接,检查资源是否已经注册到服务器,如果有必要可以修改资源。如果资源不存在,您
可以在管理控制台中创建它们。
您需要确保 PostMessage servlet 中的 JMS 连接工厂资源被映射为了已注册到 Sun Java System Application Server 的 JMS
连接工厂资源的正确 JNDI 名称。
以下资源应该注册到 Sun Java System Application Server 中:
- 拥有 JNDI 名称
jms/NewMessage 和类型
javax.jms.Queue 的一个目的地资源。
- 拥有 JNDI 名称
jms/NewMessageFactory 和类型
javax.jms.QueueConnectionFactory 的一个连接工厂资源。
参考资料
要了解使用 NetBeans IDE 6.0 开发 Java EE 应用程序的更多信息,请参考以下资源:
在
Java EE 5 教程 中,您可以找到有关 EJB 3.0
Enterprise Beans 使用方法的更多信息。
要发送意见和建议,获得支持,了解 NetBeans IDE Java EE 开发特性的最新发展,
请加入 nbj2ee 邮件列表。
|