用Java EE 5实现的网上书店实例
| 李力 (ada.li@sun.com) | 2007/10/23 |
本教程介绍了如何使用NetBeans IDE 以及GlassFish 构建一个典型的Java EE 5应用实例. 该实例模拟网上书店, 主要实现的是对订单的管理。用户可以购买图书, 并修改订单. 该实例覆盖了Java DB, JPA(Java Persistence API), EJB 3.0, JSF等技术应用. |
目录
第一部分:环境准备
第二部分:数据准备
第三部分:实现JPA层与EJB层
第四部分:实现Web层
网上商店说明
网上商店实现了商品浏览,用户可以进行订单查询,生成订单以及删除订单等操作。
教程使用环境
-
Java SE 5(或更高版本)
-
NetBeans IDE 5.5.1 中文版
-
NetBeans IDE 5.5.1 Visual Web Pack 中文版
-
Sun Java Application Server PE 9.0 Update Release 1(或更高版本)
配置Sun Java System Application Server
如果安装的 NetBeans IDE 与 Sun Java System Application Server 捆绑在一起,则表明已在 IDE 中注册了应用服务器,不需要对其进行配置。如果单独下载并安装了 Sun Java System Application Server,则必须为 IDE 配置可用的应用服务器。
配置单独安装的服务器:
-
安装 NetBeans IDE 和 Sun Java System Application Server 后,启动 IDE。
-
在"运行环境"窗口中,右键单击"服务器"节点,然后从弹出式菜单中选择"添加服务器"。
-
在"添加服务器实例"向导中,从"服务器"下拉列表中选择 "Sun Java System Application Server",然后单击"下一步"。
-
输入应用服务器的安装位置,然后单击"下一步"。
-
缺省应用服务器域 domain1 的缺省用户名和口令如下:
-
用户名:admin
-
口令:adminadmin
请注意,如果在此处指定一个口令,则系统会将其存储在用户目录中,这可能会产生安全隐患。如果未在此处指定口令,则会在需要时提示您输入口令值。
-
-
单击"完成"。
创建数据库
在这节中使用Sun Java System Application Server 捆绑的Derby数据库, 完成创建数据库,创建表,建立数据库连接池,建立数据库资源等。
创建Derby数据库
-
启动 NetBeans IDE后,如果尚未启动数据库服务器,请选择"工具"<"Java DB 数据库"<"启动 Java DB 服务器"。
-
选择"工具"<"Java DB 数据库"<"创建 Java DB 服务器"。
-
在"创建 Java DB 服务器"输入如下信息:
-
数据库名称:bookshop
-
用户名:book
-
口令: book
-
图一: 创建bookshop数据库
-
NetBeans IDE会自动在"运行环境"<"数据库"接点下建立bookshop的数据库连接。
图: bookshop数据库连接
-
如果 bookshop 数据库的 jdbc 节点标记显示为连接中断
,并且无法展开该节点,则表明 IDE 未连接到该数据库。要连接 bookshop 数据库,请右键单击 bookshop 数据库的 jdbc 节点,。如果出现"连接"对话框,请输入
book
作为口令,选中"在此会话期间记住口令",然后单击"确定"。 -
如果未出现bookshop的数据库连接, 在"运行环境"窗口中,右键单击"数据库",然后从弹出式菜单中选择"新建连接"以打开"新建数据库连接"对话框。
-
从"名称"下拉列表中选择 "Java DB (Network)"。
-
在"数据库 URL"文本框中,键入 jdbc:derby://localhost:1527/bookshop。
-
将"用户名"设置为 book,将"口令"设置为 book,然后单击"确定"。
-
在建立连接后,请单击"确定"以关闭对话框。
图2: 新建bookshop数据库连接
创建表
到这一步, bookshop数据库是全新的,因此它是空的。现在,开始添加表和数据。NetBeans IDE可以使用表向导来逐个创建表, 这个教程里使用SQL脚本.
使用SQL脚本创建表
-
右键单击bookshop
数据库下的表节点,
然后从弹出式菜单中选择"执行命令"
。 -
在新打开的"SQL
点击"运行SQL"按钮, 运行成功的话,可以在bookshop 数据库连接的"表"节点,看到新生成三个表。命令1"
窗口中,
输入以下SQL。
create table "BOOK"."CUSTOMER"
(
"CUSTOMER_ID" CHAR ( 12 ) not null primary key ,
"CUSTOMER_NAME" VARCHAR ( 30 ),
"EMAIL" VARCHAR ( 40 )
);
insert into customer values ( ' ada ' , ' Ada Li ' , ' ada.li@sun.com ' );
insert into customer values ( ' joey ' , ' Joey Shen ' , ' joey.shen@sun.com ' );
insert into customer values ( ' michael ' , ' Michael Li ' , ' tao.li@sun.com ' );
create table "BOOK"."PRODUCT"
(
"PRODUCT_ID" INTEGER not null primary key ,
"PRODUCT_NAME" VARCHAR ( 100 ),
"PURCHASE_COST" DECIMAL ( 12 , 2 )
);
insert into product values ( 1 , ' Java(TM) EE 5 Tutorial ' , 34.64 );
insert into product values ( 2 , ' Java EE 5 Development using Glassfish Application Server ' , 32.50 );
insert into product values ( 3 , ' Enterprise JavaBeans 3.0 ' , 31.49 );
insert into product values ( 4 , ' Sun Certified Enterprise Architect for Java EE study Guide ' , 32.99 );
insert into product values ( 5 , ' Java ME Game Programming ' , 49.99 );
create table "BOOK"."PURCHASE_ORDER"
(
"ORDER_NUM" INTEGER not null primary key ,
"CUSTOMER_ID" CHAR ( 12 ) not null ,
"PRODUCT_ID" INTEGER not null ,
"QUANTITY" SMALLINT
);
insert into PURCHASE_ORDER values ( 1 , ' ada ' , 1 , 1 );
insert into PURCHASE_ORDER values ( 2 , ' ada ' , 5 , 1 );
insert into PURCHASE_ORDER values ( 3 , ' joey ' , 2 , 2 );
-
CUSTOMER
-
PRODUCT
-
PURCHASE_ORDER
-
-
右键单击表或列,然后从弹出式菜单中选择"查看数据",可以查看表和列中的数据。
配置JDBC 连接池和JDBC资源
数据库连接池是服务器为特定的数据库提供的一组可重用的连接。请求数据库连接的应用程序将从该池中获取连接。当应用程序关闭某个连接后,该连接将会返回到连接池中。连接池属性可能随数据库供应商的不同而有所不同。一些公共属性包括数据库名称的 URL、用户名和口令等。
建立数据库连接池时,还将创建 JDBC 资源(也称为数据源)。JDBC 资源为应用程序提供了数据库连接。通常,应用程序所访问的每个数据库都至少有一个 JDBC 资源。一个数据库可以有多个 JDBC 资源。
下面介绍如何在Sun Java System Application上配置 JDBC 连接池和JDBC 资源
1.启动Sun Java System Application, 在NetBeans IDE的"运行环境"窗口中的"服务器"节点下, 右键单击"Sun Java System Application", 选择"启动"
2.在浏览器地址窗口中,输入"http://localhost:4848", 出现管理控制台登录界面. 缺省的管理员/密码: admin/adminadmin
配置 JDBC 连接池
接下来,将为bookshop数据库创建一个 JDBC 连接池,并定义数据库连接的特性。
-
在管理控制台的左窗格中,展开"资源"< "JDBC",然后选择"连接池"。
-
在"连接池"页中,单击"新建"以创建新的连接池。
-
在"创建连接池"向导的第一步, 输入和选择如下内容。
名称:bookshopPool
资源类型:javax.sql.XADataSource
数据库供应商:JavaDB
点击"下一步按钮"。 -
在"创建连接池"向导的第二步,找到属性部分,修改以下属性值。
DatabaseName: bookshop
User: book
Password: book
ServerName:localhost
PortNumber:1527
-
属性设置完成后,点击同一页面"ping"按钮,测试设置是否正确。如果正确,会显示"Ping 成功 "的信息. -
点击"完成"按钮,在Sun Java Application Server 中创建bookshopPool连接池.
配置 JDBC 资源
必须为bookshop创建一个 JDBC 资源,以便让部署后的应用程序能够通过它连接到bookshop数据库。
-
在管理控制台的左窗格中,展开"资源"< "JDBC",然后选择"JDBC 资源"。"资源"< "JDBC" <"JDBC 资源"页将在右窗格中打开。
-
单击"新建"。用于创建新 JDBC 资源的页将出现在右窗格中, 输入或选择如下内容。
JNDI名称:jdbc/bookshopDS
池名称:bookshopPool
-
点击"确定"按钮,在Sun Java Application Server 中创建JDBC 资源 jdbc/bookshopDS.
NetBeans IDE中可以直接创建JDBC 连接池和JDBC 资源
如果要将应用程序部署到 Sun Java System Application Server,则在 IDE 中使用"新建文件"向导可以轻松地建立数据库连接池和所需的数据源。通过在 IDE 中打开"新建文件"向导,选择"Sun 资源"类别,然后选择要创建的资源类型,可以为应用程序创建 JDBC 资源和连接池。使用"新建文件"向导可以执行以下操作:
当使用"新建文件"向导建立连接池时,IDE 将基于指定的连接生成所需的文件。在将应用程序部署到服务器时,会在 Sun Java System Application Server 中注册资源。
如果要将应用程序部署到 Sun Java System Application Server 以外的服务器,则需要通过编辑资源的源文件来建立资源。
创建企业项目
-
NetBeans IDE中,选择"文件"<"新建项目"(Ctrl-Shift-N)。从 "企业" 类别中选择"企业应用程序",然后单击"下一步"。
-
将项目命名为 BookshopApp,将服务器设置为 "Sun Java System Application Server",将 Java EE 版本设置为 "Java EE 5",然后单击"完成"。
-
在NetBeans IDE的"项目"窗口中,会出现三个项目
BookshopAppBookshopApp-ejb
BookshopApp-war
持久层
Java EE 5 平台引入了新的 Java 持久性 API(它是作为 JSR-220 的一部分开发的)。Java 持久性 API 不但可以在 EJB 组件外部使用(例如,在 Web 应用程序和应用程序客户端中使用),而且还可以在 Java EE 平台之外的 Java SE 应用程序中使用。
Java 持久性 API 具有以下主要功能:
-
实体是 POJO。与使用容器管理持久性 (Container-Managed Persistence, CMP) 的 EJB 组件不同,使用新 API 的实体对象不再是组件,并且它们不再需要位于 EJB 模块中。
-
标准化的对象关系映射。新规范将对对象关系映射的处理方式进行标准化,从而使开发者不再需要了解特定于供应商的策略。Java 持久性 API 使用标注来指定对象关系映射信息,但它仍支持 XML 描述符。
-
命名查询。现在命名查询是用元数据表示的静态查询。查询可以是 Java 持久性 API 查询或本地查询。这样会使重用查询变得非常简单。
-
简单的打包规则。由于实体 Bean 是简单的 Java 技术类,因此几乎可以在 Java EE 应用程序中的任意位置将其打包。例如,实体 Bean 可以是 EJB
JAR
、应用程序客户端JAR
、WEB-INF/lib
、WEB-INF/classes
的一部分,甚至是企业应用程序归档 (Enterprise Application Archive, EAR) 文件中实用程序JAR
的一部分。通过这些简单的打包规则,您不再需要创建 EAR 文件以使用来自 Web 应用程序或应用程序客户端的实体 Bean。 -
分离的实体。由于实体 Bean 是 POJO,因此可以对它们执行序列化,通过网络将其发送到其他地址空间,并在不识别持久性的环境中使用它们。这样,您就不再需要使用数据传输对象 (Data Transfer Object, DTO)。
-
EntityManager API。现在,应用程序编程人员可以使用标准 EntityManager API 来执行涉及实体的
创建、读取、更新和删除
(Create Read Update Delete, CRUD) 操作。
IDE 提供了处理新 Java 持久性 API 的工具。您可以通过数据库自动生成实体类,或手动对实体类进行编码。IDE 还提供了用于创建和维护持久性单元的模板和图形编辑器。
创建持久性单元
持久性单元目的在于通知容器哪些实体类需要由实体管理器进行管理,以及这些实体需要使用哪些数据源信息。
-
在"项目"窗口中右键单击 "BookshopApp-ejb" 项目节点,然后选择"新建"<"文件/文件夹"以打开"新建文件"向导。
-
从"持久性"类别中,选择"持久性单元",然后单击"下一步", 配置信息如
持久性单元名称:BookshopApp-ejbPU
持久性提供程序: TopLink(缺省)
数据源: jdbc/bookshopDS
使用 使用 Java 事务 API : 是
表生成策略: 无
-
单击"完成", 最后生成BookshopApp-ejb项目下生成persistence.xml, 这个文件中定义了持久性单元的属性。
创建实体类
实体类用于表示要创建的关系数据库中的表。下面为bookshop数据库中的三张表创建实体类,实体类包括命名的查询标注、表示列的字段以及表示外键的关系。
-
右键单击 "BookshopApp-ejb" 项目节点,然后选择"新建"<"文件/文件夹"。
-
从"持久性"类别中,选择"通过数据库生成实体类",然后单击"下一步"。
-
下一个窗口中, "数据源"选择"jdbc/bookshopDS", 点击"全部添加"按钮, 将"可用表"中的三张表(CUSTOMER, PRODUCT, PURCHASE_ORDER)添加到"选定表"中, 点击"下一步"按钮。
-
下一个窗口中,输入包名"bookshop.entities",点击完成。
生成的Product实体类的部分代码如下:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
实体类是一个简单的 Java 类。 @Entity 标注以将该类定义为实体类,其它标注的解释和说明可以查看相关文档。
EJB层
使用新的 EJB 3.0 API,可以减少并简化开发者需要完成的工作量,从而可以更轻松地进行软件开发。换句话说,就是使用了更少的类和代码。这是因为现在容器承担了更多的工作,从而实现了这一目的。下面是新 EJB 3.0 API 的一些功能和优点:
-
只需很少的类和接口。您不再需要 EJB 组件的 Home 接口和对象接口,因为现在容器负责公开必要的方法。您只需提供业务接口。您可以使用标注来声明 EJB 组件,并且通过容器来管理事务。
-
不再需要部署描述符。您可以在类中直接使用标注,为容器提供以前在部署描述符中定义的依赖关系和配置信息。如果没有任何特殊说明,容器将使用缺省规则来处理最常见的情况。
-
查找简单。您可以通过
EJBContext
直接在类中查找 JNDI 名称空间中的对象。 -
简化了对象关系映射。新的 Java 持久性 API 允许您使用 POJO 中的标注将 Java 对象映射到关系数据库,从而使对象关系映射变得更简单透明。
在 IDE 中,您可以对 Enterprise Beans 进行编码,就像对其他 Java 类进行编码一样,方法是:使用代码完成和编辑器提示实现正确的方法并使类与其接口保持同步。您不必使用特殊命令和对话框生成诸如业务方法或 Web 服务操作之类的内容,虽然这些命令仍可以帮助您熟悉 Java EE 5 代码的语法。
创建会话Bean
为 Product
实体类创建一个会话Bean
。
-
右键单击 EJB 模块,然后选择"新建"<"文件/文件夹"。
-
从"持久性"类别中,选择"实体类的会话 Bean",然后单击"下一步"。
-
从可用的实体类列表中,选择 "Product",单击"添加",然后单击"下一步"。
-
包名设置为"bookshop.ejb", 选择"创建本地接口"。 -
单击"完成"。
单击"完成"后,将创建会话Bean 类和接口(ProductFacade.java,ProductFacadeLocal.java)。
ProductFacade.java代码如下。
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/7ff8d92cded7e0ce15e7ca1acc870052.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/7ff8d92cded7e0ce15e7ca1acc870052.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/7ff8d92cded7e0ce15e7ca1acc870052.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/7ff8d92cded7e0ce15e7ca1acc870052.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/7ff8d92cded7e0ce15e7ca1acc870052.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/7ff8d92cded7e0ce15e7ca1acc870052.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/7ff8d92cded7e0ce15e7ca1acc870052.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
其中,标注 @Stateless 用于将类声明为无态会话 Bean 组件。标注@PersistenceContext表明,PersistenceContext 资源已直接注入到会话 Bean 组件中。
Web层
Web
层实现方式很多,这个教程里给出两种方式。一种是简单的Servlet,
来显示Product
信息,
另外一种是使用Visual Web Pack
,实现对订单的管理。
创建Servlet
-
在"项目"窗口中,右键单击 BookshopApp-war 节点,然后选择"新建"< "Servlet"。
-
类名:ProductServlet,包名:bookshop.web。单击"下一步"。
-
在下一个"配置Servlet部署"窗口中,单击"完成"按钮。
-
在 ProductServlet 源代码编辑器中, 任意位置单击鼠标右键,选择"企业资源"<"调用 Enterprise Bean"。
-
在"调用Enterprise Bean"窗口中,选择"BookshopApp-ejb" -< "ProductFacade",点击完成。
-
这一步骤之后,IDE会在 ProductServlet.java代码中,插入语句"@EJB private ProductFacadeLocal productFacade;",表示对EJB的声明和引用。
-
修改后的 ProductServlet.java代码如下:
-
......
public class ProductServlet extends HttpServlet ... {
@EJB
private ProductFacadeLocal productFacade;
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException ...{
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println(">html<");
out.println(">head<");
out.println(">title /title< ");
out.println(">/head<");
out.println(">body<");
java.util.List list = productFacade.findAll();
java.util.Iterator products = list.iterator();
while (products.hasNext())...{
bookshop.entities.Product obj = (bookshop.entities.Product) products.next();
out.println(">h2 " + obj.getProductId() + " : " + obj.getProductName() + ">/h2<");
};
out.println(">/body<");
out.println(">/html<");
out.close();
}
......
运行企业应用程序
在"项目"窗口中,右键单击 BookshopApp项目, 并选择"运行项目"。 IDE 会执行以下所有任务:
-
生成企业应用程序项目及其所有子项目(Web 模块项目和 EJB 模块项目)。
-
如果服务器尚未运行,启动它。
-
如果企业应用程序已部署到应用服务器上,卸下它。
-
将企业应用程序部署到应用服务器上。
-
打开在指定的相对 URL 中的 Web 模块。
浏览器中自动打开的URL是"http://localhost:8080/BookshopApp-war/",显示空白的index.jsp, 修改URL为"http://localhost:8080/BookshopApp-war/ProductServlet",运行结果如下:
JSF与NetBeans Visual Web Pack
JSF(Java Server Faces)是Web应用程序的一种框架,而NetBeans Visual Web Pack是工具,实现了JSF的可视化编程.
下面介绍了使用NetBeans Visual Web Pack开发网上商店的Web层,实现如下功能.
-
浏览商品
-
根据用户名查询对应订单
-
生成订单
-
删除订单
创建Visual Web Pack项目
创建Visual Web
项目
-
IDE中选择"文件"<"新建项目"来创建一个项目。在"类别"窗格中选择 "Web",然后在"项目"窗格中选择"Visual Web 应用程序",单击"下一步"。
-
在"新建Visual Web应用程序 "窗口中,输入如下内容:
项目名称:BookshopApp-vwp
项目位置: 建议在BookshopApp目录下
服务器: Sun Java System Application Server
Java EE 版本: Java EE 5
-
单击"完成",生成BookshopApp-vwp项目文件夹及相关文件。
把BookshopApp-vwp
项目加入到BookshopApp
企业应用程序项目中
-
右键单击
BookshopApp
项目,选择"属性".
-
在"选择项目"窗口中,浏览选择"B
"文件夹,"项目JAR
文件"栏目下出现"dist/BookshopApp-vwp.war
",
点击"添加
项目
JAR
文件
"按钮.ookshopApp-vwp
-
在"项目属性"窗口中,选择左侧栏中"生成"->"打包",点击右侧栏中"添加项目"按钮.
-
返回到
"项目属性"窗口,点击"确定"按钮.
在BookshopApp-vwp
项目中引用BookshopApp-ejb
项目
-
右键单击
BookshopApp-vwp
项目,选择"属性".
-
在出现的"项目属性
BookshopApp-vwp
"窗口中,"类别"选择"库",右侧栏目中选择"添加项目".
-
在新出现的"添加项目"窗口中,浏览选择"BookshopApp-ejb
",
点击"添加项目JAR
"文件.
-
返回到
"项目属性
BookshopApp-vwp
"窗口,点击"确定"按钮.
测试
-
右键单击
BookshopApp
项目,选择"部署项目".
-
成功部署后,可以在"运行环境"->"服务器"->"Sun Java System Application Server
"->"应用程序"->"企业应用程序"下,看到"BookshopApp
"及子模块.
浏览商品
之前用Servlet实现了浏览商品的功能,接下来在Page1.jsp页面上利用JSF组件实现同样功能.
将组件添加到Web页面
-
通过将组件从"组件面板"窗口拖放到可视设计器中的Web
页上,如"按钮"、"静态文本"、"表"、"下拉列表" 都属于组件面板的"基本"类别.
-
更改这些组件的属性对其进行了定制。
配置下拉列表
-
打开"运行环境"窗口,展开"数据库"节点并检查是否已连接 bookshop 数据库。
-
展开 bookshop 数据库的 jdbc 节点,然后展开"表"节点。
-
将 "CUSTOMER" 节点拖动到可视设计器的下拉列表上。
-
拖动成功的话,下拉列表会显示"abc"内容,"概要"窗口的 "Page1" 部分中将显示 "CustomerDataProvider" 节点,"SessionBean1" 部分中将显示 "CustomerRowSet" 节点。
-
右键单击"下拉列表"组件,然后从弹出式菜单中选择"绑定到数据"。
-
在"绑定到数据"窗口,"值字段"选择"CUSTOMER.CUSTOMER_ID","显示字段"选择"CUSTOMER.CUSTOMER_NAME",点击"确定"按钮.
配置表
-
将 "bookshop" 数据库节点 <"表"< "PRODUCT" 节点从"运行环境"窗口拖放到可视设计器中的"表"组件上。如果显示"选择目标"对话框,请确保选择 table1,然后单击"确定"。
-
拖动成功的话,表的显示内容会改变,"概要"窗口的 "Page1" 部分中将显示 "ProductDataProvider" 节点,"SessionBean1" 部分中将显示 "ProductRowSet" 节点。
-
右键单击该表,然后从弹出式菜单中选择"表布局",在"表布局"对话框里修改"表头文字"等信息.。
测试
-
右键单击
BookshopApp
项目,选择"部署项目".
-
在浏览器中输入URL: "http://localhost:8080/BookshopApp-vwp/"
,显示如下结果,下拉列表中显示的是CUSTOMER
数据表的内容,而"图书列表"显示的是PRODUCT
数据表的内容.
根据用户名查询订单
从下拉列表中选择用户,点击"查询"按钮,可以显示出该用户的订单内容.
创建新页OrderList
-
在"项目"窗口中,右键单击"BookshopApp-vwp"
节点,然后选择"新建"-<"
页"。
-
文件名输入"OrderList
",然后单击"完成",在web
下创建OrderList.jsp
文件.
-
将"静态文本","文本字段"和"表"三个组件从"组件面板"窗口拖放到可视设计器中的OrderList
页上,
修改相关属性
.
配置表
-
将 "bookshop"
数据库节点 <"
表"< "PURCHASE_ORDER"
节点从"运行环境"窗口拖放到
OrderList
页上
可视设计器中的"表"组件上。 -
拖动成功的话,表的显示内容会改变,"概要"窗口的 "Page1"
部分中将显示 "purchase_orderDataProvider"
节点,"SessionBean1"
部分中将显示 "perchase_orderRowSet"
节点。
-
在"概要"窗口中,右键单击 "SessionBean1"
下的 "
perchase_orderRowSet
",然后从弹出式菜单中选择"编辑 SQL
语句"。
这将打开 SQL 查询编辑器。 -
将 "bookshop"
数据库节点 <"
表"< "PRODUCT"
节点
从"运行环境"窗口拖放到 SQL
查询编辑器 上面的窗口中.
-
在窗口中心附近的网格区域,选择"CUSTOMER_ID"
行,在"条件"栏中输入"=?"(注意输入时,切换到英文状态).取消"BOOK.PRODUCT.PRODUCT_ID
"的显示.
-
修改SQL
语句,联合PURCHASE_ORDER
和PRODUCT
两个表,点击IDE
菜单上的"保存"按钮
-
SELECT ALL BOOK.PURCHASE_ORDER.ORDER_NUM,
BOOK.PURCHASE_ORDER.CUSTOMER_ID,
BOOK.PURCHASE_ORDER.PRODUCT_ID,
BOOK.PURCHASE_ORDER.QUANTITY,
BOOK.PRODUCT.PRODUCT_NAME,
BOOK.PRODUCT.PURCHASE_COST
FROM BOOK.PURCHASE_ORDER, BOOK.PRODUCT
WHERE BOOK.PURCHASE_ORDER.CUSTOMER_ID = ?
AND BOOK.PURCHASE_ORDER.PRODUCT_ID = BOOK.PRODUCT.PRODUCT_ID
-
-
打开OrderList.jsp
的
可视设计器,右键单击表,然后从弹出式菜单中选择"表布局",在"表布局"对话框里增加修改字段,修改"表头文字"等信息
-
OrderList.jsp
显示如下:
传递参数
接下来的步骤需要把Page1.jsp中的用户名传给OrderList.jsp"订单列表"的SQL查询.
首先,确定利用RequestBean来传递参数,打开Page1.jsp页面,
-
右键单击"概要"窗口中的 "RequestBean1" 节点,然后选择"添加"<"属性"。如果没有出现"添加"菜单项,请按 Esc 键,然后再次右键单击该节点。将属性命名为
customerId
,将其类型设置为String
,然后单击"确定"。请注意,新添加的属性可能没有显示在"概要"窗口中。要显示该属性,请在可视设计器中单击鼠标右键,然后从弹出式菜单中选择"刷新"。也可以按照以下步骤所述,打开并保存 RequestBean1 源文件以显示该属性。 -
在"概要"窗口中,右键单击"RequestBean1",然后从弹出式菜单中选择"编辑 Java 源代码"。 -
滚动到源文件底部以查看 IDE 为属性添加的
getCustomerId
和setCustomerId
方法。 -
保存并关闭该文件。
-
打开Page1.jsp可视设计器,双击"查询"按钮,打开Page1.jsp源文件窗口,光标停留在" public String button1_action() "方法内,修改内容如下:
-
public String button1_action() ... {
// 待做事项:处理操作。返回的值是一个导航
// 如果名称为 null,则返回到同一页。
getRequestBean1().setCustomerId((String)dropDown1.getValue());
return null;
}
-
打开OrderList.jsp的Java源代码窗口,找到"prerender()"方法,修改内容如下:
-
public void prerender() ... {
String customerId = getRequestBean1().getCustomerId();
if (customerId != null)...{
textField1.setText(customerId);
try ...{
getSessionBean1().getPurchase_orderRowSet().setString(1,customerId);
getPurchase_orderDataProvider().refresh();
} catch (java.sql.SQLException ex) ...{
ex.printStackTrace();
}
}
}
指定页面导航
点击"BookshopApp-vwp
"项目下的"页面导航",
用鼠标拖动建立Page1.jsp
和OrderList.jsp
的跳转.
测试
-
右键单击
BookshopApp
项目,选择"部署项目".
-
在浏览器中输入URL: "http://localhost:8080/BookshopApp-vwp/"
,选择用户名,点击"查询"按钮,可以看到如下页面:
生成订单
PURCHASE_ORDER数据表里包括了订单信息,一共四个字段,ORDER_NUM, CUSTOMER_ID, PRODUCT_ID,以及QUANTITY. 在page1.jsp页面中,可以得到CUSTOMER_ID和PRODUCT_ID的信息,接下来的步骤是如何获得ORDER_NUM和QUANTITY
取得最大ORDER_NUM
-
打开Page1.jsp
可视设计器。
-
从"运行环境"窗口中选择"数据库"< "bookshop" <"表"< "PURCHASE_ORDER" 表,然后将它拖动到"概要"窗口中的 "SessionBean1" 节点上。
-
在打开的"添加新的数据提供器"对话框中, 单击"创建 SessionBean1/purchase_orderRowSet1"
单选按钮,将数据提供器的名称更改为maxOrder
,然后单击"确定"。
RowSet
-
在 SessionBean1
中创建 maxOrderDataProvider
和 maxOrderRowSet
。
-
在"概要"窗口中,双击 "SessionBean1" < "maxOrderRowSet" 以打开查询编辑器。在源代码窗格(上数第三个窗格)中单击鼠标左键。删除此处现有的 SQL 查询,然后输入以下查询后,点击"保存":
代码样例 8: maxOrderRowSet SQL
SELECT MAX(BOOK.PURCHASE_ORDER.ORDER_NUM)+1 AS MAXORDERID FROM BOOK.PURCHASE_ORDER
-
MAXORDERID值将作为新订单的ORDER_NUM。
在Page1.jsp中添加QUANTITY输入框
-
打开Page1.jsp
可视设计器。右键点击"图书列表",打开"表布局"对话框。
-
单击"列"标签,然后单击"新建",添加两个新列到表中。
-
QUANTITY输入框设置:
-
表头文本和页脚文本:数量
-
组件类型:
文本字段
-
值表达式:text
-
宽度:
-
水平对齐:
居中
-
垂直对齐:
中部
-
"购买"按钮列设置。
-
表头文本和页脚文本:
-
组件类型:
按钮
-
值表达式:删除
-
宽度:
-
水平对齐:
居中
-
垂直对齐:
中部
订单保存在数据库中
-
在page1.jsp
可视设计器中,双击"购买"按钮,以打开Java
编辑器。在Java
编辑器中,插入点将位于该按钮的buttonAddOrder_action()
事件处理程序方法中。
-
源代码编辑器中, 任意位置单击鼠标右键,选择"企业资源"<"调用 Enterprise Bean"。
-
在"调用Enterprise Bean"窗口中,选择"BookshopApp-ejb" -< "PurchaseOrderFacade",点击完成。
-
这一步骤之后,IDE会在 Page1.java代码中,生成lookupPurchaseOrderFacade()方法。修改 Page1.java代码中 方法
buttonAddOrder_action()
-
private PurchaseOrderFacadeLocal lookupPurchaseOrderFacade() ... {
try ...{
Context c = new InitialContext();
return (PurchaseOrderFacadeLocal) c.lookup("java:comp/env/ejb/PurchaseOrderFacade");
}
catch(NamingException ne) ...{
Logger.getLogger(getClass().getName()).log(Level.SEVERE,"exception caught" ,ne);
throw new RuntimeException(ne);
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
测试
-
右键单击
BookshopApp
项目,选择"部署项目".
-
在浏览器中输入URL: "http://localhost:8080/BookshopApp-vwp/"
,选择用户,
输入数量,
点击"购买"按钮.
删除订单
-
打开OrderList.jsp
可视设计器。右键点击"订单列表",打开"表布局"对话框。
-
单击"列"标签,然后单击"新建",添加一个新列到表中。
-
表头文本和页脚文本:
-
组件类型:
按钮
-
值表达式:删除
-
宽度:
-
水平对齐:
居中
-
垂直对齐:
中部
-
在
OrderList.jsp
可视设计器中,双击"删除"按钮,以打开Java
编辑器。在Java
编辑器中,插入点将位于该按钮的buttonDelete_action()
事件处理程序方法中。
-
public String buttonDelete_action() ... {
// 待做事项:处理操作。返回的值是一个导航
// 如果名称为 null,则返回到同一页。
try ...{
RowKey rk = tableRowGroup1.getRowKey();
if (rk != null) ...{
purchase_orderDataProvider.removeRow(rk);
purchase_orderDataProvider.commitChanges();
purchase_orderDataProvider.refresh();}
} catch (Exception ex) ...{
log("ErrorDescription", ex);
error(ex.getMessage());
}
return null;
}
测试
-
右键单击
BookshopApp
项目,选择"部署项目".
-
在浏览器中输入URL: "http://localhost:8080/BookshopApp-vwp/"
,选择用户,
点击"查询"按钮.
-
在下一个页面上,
点击"删除"按钮.
问题与解决
问题: No object bound to name java:comp/env/jdbc/bookshopDS
-
Sun Java System Application Server log:
StandardWrapperValve[Faces Servlet]: Servlet Faces Servlet
的 Servlet.service()
抛出异常
javax.naming.NameNotFoundException: No object bound to name java:comp/env/jdbc/bookshopDS
at com.sun.enterprise.naming.NamingManagerImpl.lookup(NamingManagerImpl.java:751)
at com.sun.enterprise.naming.java.javaURLContext.lookup(javaURLContext.java:156)
at com.sun.enterprise.naming.SerialContext.lookup(SerialContext.java:307)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
at com.sun.sql.rowset.internal.CachedRowSetXReader.connect(CachedRowSetXReader.java:332)
at com.sun.sql.rowset.internal.CachedRowSetXReader.readData(CachedRowSetXReader.java:126)
解决:
修改Web
程序中的web.xml,
添加资源引用名称jdbc/bookshopDS
参考
Http://www.netbeans.org
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1882655