| 作者:李力 (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 6.0
-
GlassFish 或Sun Java Application Server PE 9.0 Update Release 1(或更高版本)
配置GlassFish
如果安装的 NetBeans IDE 与 GlassFish 捆绑在一起,则表明已在 IDE 中注册了应用服务器,不需要对其进行配置。如果单独下载并安装了 GlassFish或者Sun Java System Application Server 9.0,则必须为 IDE 配置可用的应用服务器。
配置单独安装的服务器:
-
安装 NetBeans IDE 6.0和 GlassFish 后,启动 IDE。
-
在“Services”窗口中,右键单击“Servers”节点,然后从弹出式菜单中选择“Add Servers...”。
-
在“Add Server Instance”向导中,从“Server”栏目中选择 "GlassFish V2",然后单击“Next”。
-
输入应用服务器的安装位置”Platform Location:”,选择“Register Local Default Domain”, 然后单击“Next”。
-
缺省应用服务器域 domain1 的缺省用户名和口令如下:
-
Admin Username:admin
-
Admin Password:adminadmin
请注意,如果在此处指定一个口令,则系统会将其存储在用户目录中,这可能会产生安全隐患。如果未在此处指定口令,则会在需要时提示您输入口令值。
-
-
单击“Finish”。
创建数据库
在这节中使用GlassFish 捆绑的Derby数据库, 完成创建数据库,创建表,建立数据库连接池,建立数据库资源等。
创建Derby数据库
-
启动 NetBeans IDE后,如果尚未启动数据库服务器,请选择菜单“Tools”>“Java DB Database”>“Start Server”。
-
选择菜单“Tools”>“Java DB Database”>“Create Java DB Database”。
-
在“Create Java DB Database”输入如下信息:
-
Database Name:bookshop
-
User Name:book
-
Password: book
-
图一: 创建bookshop数据库
-
NetBeans IDE会自动在”Services”>”Databases”节点下建立bookshop的数据库连接。
图: bookshop数据库连接
-
如果 bookshop 数据库的 jdbc 节点标记显示为连接中断 ,并且无法展开该节点,则表明 IDE 未连接到该数据库。要连接 bookshop 数据库,请右键单击 bookshop 数据库的 jdbc 节点, 选择“Connect...”。
-
如果未出现bookshop的数据库连接, 在“Serivces”窗口中,右键单击“Databases”,然后从弹出式菜单中选择“New Connection...”以打开“New Database Connection”对话框。
-
从“Name”下拉列表中选择 "Java DB (Network)"。
-
在“Database URL”文本框中,键入” jdbc:derby://localhost:1527/bookshop”。
-
将“User Name”设置为 book,将“Password”设置为 book,然后单击“确定”。
-
在建立连接后,请单击“确定”以关闭对话框。
图2: 新建bookshop数据库连接
创建表
到这一步, bookshop数据库是全新的,因此它是空的。现在,开始添加表和数据。NetBeans IDE可以使用表向导来逐个创建表, 这个教程里使用SQL脚本.
使用SQL脚本创建表
-
右键单击bookshop
数据库下的表节点,
然后从弹出式菜单中选择”Execute Command”
-
在新打开的”SQL Command 1”
窗口中,
输入以下SQL。
代码样例 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);
-
点击”Run SQL”按钮(或者组合键 Ctrl+Shift+E), 运行成功的话,可以在bookshop 数据库连接的"Tables"节点,看到新生成三个表。
-
CUSTOMER
-
PRODUCT
-
PURCHASE_ORDER
-
-
右键单击表或列,然后从弹出式菜单中选择“View Data...”,可以查看表和列中的数据。
配置JDBC 连接池和JDBC资源
数据库连接池是服务器为特定的数据库提供的一组可重用的连接。请求数据库连接的应用程序将从该池中获取连接。当应用程序关闭某个连接后,该连接将会返回到连接池中。连接池属性可能随数据库供应商的不同而有所不同。一些公共属性包括数据库名称的 URL、用户名和口令等。
建立数据库连接池时,还将创建 JDBC 资源(也称为数据源)。JDBC 资源为应用程序提供了数据库连接。通常,应用程序所访问的每个数据库都至少有一个 JDBC 资源。一个数据库可以有多个 JDBC 资源。
下面介绍如何在GlassFish上配置 JDBC 连接池 和JDBC 资源
1.启动GlassFish, 在NetBeans IDE的”Services”窗口中的”Servers”节点下, 右键单击”GlassFish”, 选择”Start”
2.在浏览器地址窗口中,输入”http://localhost:4848”, 出现管理控制台登录界面. 缺省的管理员/密码: admin/adminadmin
配置 JDBC 连接池
接下来,将为bookshop数据库创建一个 JDBC 连接池,并定义数据库连接的特性。
-
在管理控制台的左窗格中,展开“Resources”> "JDBC",然后选择“Connection Pools”。
-
在“Connection Pools”页中,单击“New”以创建新的连接池。
-
在“New JDBC Connection Pool”向导的第一步, 输入和选择如下内容。
Name:bookshopPool
Resource Type:javax.sql.DataSource
Database Vendor:JavaDB
点击"Next"按钮。 -
在“New JDBC Connection Poo”向导的第二步,找到属性部分,修改以下属性值。
DatabaseName: bookshop
User: book
Password: book
ServerName:localhost
PortNumber:1527
-
属性设置完成后,点击同一页面”General”下的"ping"按钮,测试设置是否正确。如果正确,会显示"Ping Succeeded "的信息.
-
点击"Save"按钮,在 GlassFish 中创建bookshopPool连接池.
配置 JDBC 资源
必须为bookshop创建一个 JDBC 资源,以便让部署后的应用程序能够通过它连接到bookshop数据库。
-
在管理控制台的左窗格中,展开“Resources”> "JDBC" >“JDBC Resources”。
-
单击“New”。用于创建新 JDBC 资源的页将出现在右窗格中, 输入或选择如下内容。
JNDI Name:jdbc/bookshopDS
Pool Name:bookshopPool
-
点击"OK"按钮,在GlassFish中创建JDBC 资源 jdbc/bookshopDS.
创建企业项目
-
NetBeans IDE中,选择“File”>“New Project”(Ctrl-Shift-N)。从 "Enterprise" 类别中选择“Enterprise Application”,然后单击“Next”。
-
将项目命名为 BookshopApp,将服务器设置为 "GlassFish V2",将 Java EE 版本设置为 "Java EE 5",然后单击“Finish”。
-
在NetBeans IDE的"Projects"窗口中,会出现三个项目BookshopApp
BookshopApp-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 还提供了用于创建和维护持久性单元的模板和图形编辑器。
创建持久性单元
持久性单元目的在于通知容器哪些实体类需要由实体管理器进行管理,以及这些实体需要使用哪些数据源信息。
-
在“Projects”窗口中右键单击 "BookshopApp-ejb" 项目节点,然后选择“New”>“Other”以打开“New File”向导。
-
从“Categories”栏目中,选择“Persistence”,”File Types”栏目中,选择“Persistence Unit ”, 然后单击“Next”。
-
配置信息如下
Persistence Unit Name:BookshopApp-ejbPU
Persistence Provider: TopLink(缺省)
Data Source: jdbc/bookshopDS
Use Java Transaction APIs : Yes
Table Generation Strategy: None
-
单击“完成”, 最后生成BookshopApp-ejb项目下生成persistence.xml, 这个文件中定义了持久性单元的属性。
创建实体类
实体类用于表示要创建的关系数据库中的表。下面为bookshop数据库中的三张表创建实体类,实体类包括命名的查询标注、表示列的字段以及表示外键的关系。
-
右键单击 "BookshopApp-ejb" 项目节点,然后选择“New”>“Other”以打开“New File”向导。
-
从“Categories”栏目中,选择“Persistence”,”File Types”栏目中,选择“Entites from Classes ”, 然后单击“Next”。
-
下一个窗口中, “Data Source”选择”jdbc/bookshopDS”, 点击”Add all”按钮, 将”Available Tables”中的三张表(CUSTOMER, PRODUCT, PURCHASE_ORDER)添加到”Selected Tables”中, 点击”Next”按钮。
-
下一个窗口中,输入包名“bookshop.entities”,点击完成。
生成的Product实体类的部分代码如下:
-
代码样例 2:Product实体类
...... @Entity @Table(name = "PRODUCT") @NamedQueries( { @NamedQuery(name = "Product.findByProductId", query = "SELECT p FROM Product p WHERE p.productId = :productId"), @NamedQuery(name = "Product.findByProductName", query = "SELECT p FROM Product p WHERE p.productName = :productName"), @NamedQuery(name = "Product.findByPurchaseCost", query = "SELECT p FROM Product p WHERE p.purchaseCost = :purchaseCost") }) public class Product implements Serializable { @Id @Column(name = "PRODUCT_ID", nullable = false) private Integer productId; @Column(name = "PRODUCT_NAME") private String productName; @Column(name = "PURCHASE_COST") private Long purchaseCost; ......
实体类是一个简单的 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 模块,然后选择“New”>“Other”以打开“New File”向导。
-
从“Categories”栏目中,选择“Persistence”,”File Types”栏目中,选择“Session beans for entities”, 然后单击“Next”。
-
从”Available Entity Classes”列表中,选择 "bookshop.entities.Product"和"bookshop.entities.PurchaseOrder",单击“Add”,然后单击“Next”。
-
包名设置为“bookshop.ejb”, “Create Interfaces”选择“Local“。
-
单击“Finish”。
单击“Finish”后,将创建会话Bean 类和接口
-
ProductFacade.java
-
ProductFacadeLocal.java
-
PurchaseOrderFacade.java
-
PurchaseOrderFacadeLocal.java
ProductFacade.java代码如下。
-
代码样例 3:ProductFacade类
package bookshop.ejb; import bookshop.entities.Product; import java.util.List; import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; /** * * @author Sun */ @Stateless public class ProductFacade implements ProductFacadeLocal { @PersistenceContext private EntityManager em; /** Creates a new instance of ProductFacade */ public ProductFacade() { } public void create(Product product) { em.persist(product); } public void edit(Product product) { em.merge(product); } public void destroy(Product product) { em.merge(product); em.remove(product); } public Product find(Object pk) { return (Product) em.find(Product.class, pk); } public List findAll() { return em.createQuery("select object(o) from Product as o").getResultList(); } }
其中,标注 @Stateless 用于将类声明为无态会话 Bean 组件。标注@PersistenceContext表明,PersistenceContext 资源已直接注入到会话 Bean 组件中。
Web层
Web
层实现方式很多,这个教程里给出三种方式。一种是简单的Servlet,
来显示Product
信息,
另外一种是使用Visual Web JSF Page
,实现对订单的查询,添加和删除,第三种是采用jMaki
中的AJAX
组件Data Table
来显示
Product
信息。
创建Servlet
-
在“Project”窗口中,右键单击 BookshopApp-war 节点,然后选择“New”>“Other”>”Web”-> "Servlet", 点击“Next”。
-
类名:ProductServlet,包名:bookshop.web。单击“Next”。
-
在下一个“Configure Servlet Deployment”窗口中,单击“Finish”按钮。
-
在 ProductServlet 源代码编辑器中, 任意位置单击鼠标右键,选择“Enterprise Resource”>“Call Enterprise Bean”。
-
在“Call Enterprise Bean”窗口中,选择“BookshopApp-ejb” -> “ProductFacade”,点击完成。
-
这一步骤之后,IDE会在 ProductServlet.java代码中,插入语句“@EJB private ProductFacadeLocal productFacade;”,表示对EJB的声明和引用。
-
修改后的 ProductServlet.java代码如下:
-
代码样例 4: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>ProductServlet</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("<h3>Book " + obj.getProductId() + " | " + obj.getProductName() + " | " + obj.getPurchaseCost() + "</h3>"); }; out.println("</body>"); out.println("</html>"); out.close(); } ......
部署及运行企业应用程序
部署BookshopApp
-
在“Project”
窗口中,右键单击BookshopApp
项目,
并选择“Undeploy and Deploy”
-
成功部署后,可以在"Services
"->"Server
"->"GlassFish V2
"->"Applications
"->"
Enterprise Applications
"下,看到"BookshopApp
"及子模块
运行BookshopApp
在“Project”窗口中,右键单击 BookshopApp项目, 并选择“Run”。 IDE 会执行以下所有任务:
-
生成企业应用程序项目及其所有子项目(Web 模块项目和 EJB 模块项目)。
-
如果服务器尚未运行,启动它。
-
如果企业应用程序已部署到应用服务器上,卸下它。
-
将企业应用程序部署到应用服务器上。
-
打开在指定的相对 URL 中的 Web 模块。
浏览器中自动打开的URL是"http://localhost:8080/BookshopApp-war/",显示空白的index.jsp, 修改URL为"http://localhost:8080/BookshopApp-war/ProductServlet",运行结果如下:
JSF (Jave Server Faces)
JSF(Java Server Faces)是Web应用程序的一种MVC框架.Visual Web JSF Page 是可视化的JSF页面和组件。
下面介绍了使用NetBeans Visual Web JSF Page开发网上商店的Web层,实现如下功能.
-
浏览商品
-
根据用户名查询对应订单
-
生成订单
-
删除订单
浏览商品
之前用Servlet实现了浏览商品的功能,接下来在Page1.jsp页面上利用JSF组件实现同样功能.
新建Visual Web JSF Page
-
右键单击BookShopApp-war
项目,选择””Visual Web JSP page
-
在”New Visual Web Page“
窗口中,输入
-
File Name: Page1.jsp
-
Default Java Package: bookshop.web
-
点击”“Finish
按钮。在
bookShopApp-war
项目中生成了两个文件
-
web pages/Page1.jsp
(
JSF UI component
)
-
Source packages/bookshop.web/Page1.java
(JSF Managed Bean
)
如果是在项目中第一次生成Visual Web JSF Page,
那么NetBeans
还自动为项目导入”“Visual Web JavaServer Faces”
框架。除在项目中添加了相关库之外,在项目的””Source Packages”
下也自动生成如下Java
类,
这些类用于保存不同作用范围的参数和变量:
-
ApplicationBean1.java
-
SessionBean1.java
-
RequestBean1.java
将组件添加到Web页面
-
通过将组件从“Palette”
窗口拖放到可视设计器中的Web
页上,如“Static Text”
、“Button”
、“Drop Down List”
、“Table”
都属于组件面板的“Basic”
类别.
-
更改这些组件的属性对其进行了定制。
配置下拉列表组件(Drop Down List)
-
打开“Services”窗口,展开“Databases”节点并检查是否已连接 bookshop 数据库。
-
展开 bookshop 数据库的 jdbc 节点,然后展开“Table”节点。
-
将 "CUSTOMER" 节点拖动到可视设计器的”Drop Down List”上。
-
拖动成功的话,下拉列表会显示"abc"内容,“Navigator”窗口的 "Page1" 部分中将显示 "CustomerDataProvider" 节点,"SessionBean1" 部分中将显示 "CustomerRowSet" 节点。
-
Page1.jsp的”Design“页面上,右键单击“Drop Down List”组件,然后从弹出式菜单中选择“Bind to Data”。
-
在"Bind to Data"窗口,"Value Field"选择"CUSTOMER.CUSTOMER_ID","Display field"选择"CUSTOMER.CUSTOMER_NAME",点击"OK"按钮.
配置表组件(Table
)
-
将 "bookshop" 数据库节点 >“Table”> "PRODUCT" 节点从“Services”窗口拖放到Page1.jsp 的“Design”面板上的“Table”组件中。如果显示“Display Target”对话框,请确保选择 table1,然后单击“OK”。
-
拖动成功的话,表的显示内容会改变,“Navigator”窗口的 "Page1" 部分中将显示 "ProductDataProvider" 节点,"SessionBean1" 部分中将显示 "ProductRowSet" 节点。
-
右键单击该表,然后从弹出式菜单中选择“Table Layout”,在"Table Layout"对话框里修改Head text, Table Title等信息,并调整字段的显示顺序.。
测试
-
右键单击
BookshopApp
项目,选择"Undeploy and Deploy
".
-
在浏览器中输入URL: “http://localhost:8080/BookshopApp-war/”
,显示如下结果,Drop Down List
中显示的是CUSTOMER
数据表的内容,而"Book List
"显示的是PRODUCT
数据表的内容.
根据用户名查询订单
从下拉列表中选择用户,点击"Search"按钮,可以显示出该用户的订单内容。实现这个功能,分为以下几步:
-
创建一个新页OrderList.jsp来显示查询结果
-
从page1.jsp传递用户名到OrderList.jsp
-
设置Page1.jsp到OrderList.jsp的导航
创建新页OrderList
-
在“Project”
窗口中,右键单击”BookshopApp-war”
节点,然后选择“New”->“Visual Web JSF Page”
。
-
文件名输入"OrderList
",然后单击“Finish”
,在web
下创建OrderList.jsp
文件.
-
将"Static Text
","Text Field
"和"Table
"三个组件从“Palette”
窗口拖放到可视设计器中的OrderList
页上,
修改相关属性
.
配置表
-
将 "bookshop"
数据库节点 >“Table”> "PURCHASE_ORDER"
节点从“Services”
窗口拖放到
OrderList
页上
可视设计器中的“Table”组件上。
-
拖动成功的话,表的显示内容会改变,“Navigagor”
窗口的 "OrderList1"
部分中将显示 "purchase_orderDataProvider"
节点,"SessionBean1"
部分中将显示 "perchase_orderRowSet"
节点。
-
在“Navigator”
窗口中,右键单击 "SessionBean1"
下的 "
perchase_orderRowSet
",然后从弹出式菜单中选择“Edit SQL Statment”
。
这将打开 SQL 查询编辑器。 -
将 "bookshop"
数据库节点>“Table”> "PRODUCT"
节点
从“Services”
窗口拖放到SQL
查询编辑器上面的窗口中.或者在
SQL
查询编辑器上面的窗口中,
右键单击,选择”Add Table”,
从“Select Table(s) to Add”
中选择“BOOKS.PRODUCT”.
这样做是希望联合两个表,以便在OrderList.jsp
中显示更全的信息。
-
在窗口中心附近的网格区域,选择"CUSTOMER_ID”
行,在"Criteria
"栏中输入"=?"(注意输入时,切换到英文状态), “Order”
选择”1”.
取消"BOOK.PRODUCT.PRODUCT_ID
"的显示.
-
修改SQL
语句,联合PURCHASE_ORDER
和PRODUCT
两个表,点击IDE
菜单上的"Save
"按钮
代码样例 5: SQL 查询编辑器
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
的
可视设计器,右键单击表,然后从弹出式菜单中选择“Table Layout”
,在"Table Layout
"对话框里增加修改字段,以显示PRODUCT
表中的一些信息.
传递参数
接下来的步骤需要把Page1.jsp中的用户名传给OrderList.jsp"perchase_orderRowSet
"的SQL查询.
首先,确定利用RequestBean来传递参数,打开Page1.jsp页面,
-
右键单击“Navigator”窗口中的 "RequestBean1" 节点,然后选择“Edit Java Source”。 保存并关闭该文件。
代码样例6:RequestBean1.java
private String customerId; public String getCustomerId() { return customerId; } public void setCustomerId(String customerId) { this.customerId = customerId; }
-
打开Page1.jsp可视设计器,双击"Search"按钮,打开Page1.jsp源文件窗口,光标停留在" public String button1_action() "方法内,修改内容如下:.
代码样例6: Page1.jsp
public String button1_action() { // TODO: Process the action. Return value is a navigation // case name where null will return to the same page. getRequestBean1().setCustomerId((String)dropDown1.getValue()); return "case1"; }
-
打开OrderList.jsp的Java源代码窗口,找到"prerender()"方法,prerender()是在JSP页面显示前被调用,因此适合在这个方法内传入参数。另外,”Return”按钮的返回值修改为“Case1“,是为了下面的页面导航作准备。 OrderList.jsp修改内容如下:
-
代码样例 7: OrderList.jsp
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(); } } } ......
public String button1_action() {
// TODO: Process the action. Return value is a navigation
// case name where null will return to the same page.
return "case1";
}
指定页面导航
点击"BookshopApp-war
"项目下的"Page1.jsp”,
右键盘点击设计面板任意位置,选择”Page Navigation”
, 出现”Page Flow的设计面板。鼠标拖动来完成页面导航。这里的导航支持JavaServer Faces, JSP, 和HTML文件.
”
测试
-
右键单击
BookshopApp
项目,选择"Undeploy and Deploy
".
-
在浏览器中输入URL: “http://localhost:8080/BookshopApp-war/”
,选择用户名,点击"Search
"按钮,可以看到如下页面:
生成订单
实现生成订单,分为两步:
-
得到新订单的信息
-
把新订单信息保存到数据库
PURCHASE_ORDER数据表里包括了订单信息,一共四个字段,ORDER_NUM, CUSTOMER_ID, PRODUCT_ID,以及QUANTITY. 在page1.jsp页面中,可以得到CUSTOMER_ID和PRODUCT_ID的信息,ORDER_NUM是表的主键, 通常加入新纪录时, 主键值为当前最大主键值加1. 接下来的步骤是如何获得最大ORDER_NUM和QUANTITY
取得最大ORDER_NUM
-
打开Page1.jsp
可视设计器。
-
从“Services”窗口中选择“Databases”> "bookshop" >“Table”> "PURCHASE_ORDER" 表,然后将它拖动到“Navigator”窗口中的 "SessionBean1" 节点上。
-
在打开的“添加新的数据提供器”对话框中, 单击“创建 SessionBean1/purchase_orderRowSet1”
单选按钮,将数据提供器的名称更改为maxOrder
,然后单击“确定”。
RowSet
-
在 SessionBean1
中创建 maxOrderDataProvider
和 maxOrderRowSet
。
-
在“Navigator”窗口中,双击 "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
可视设计器。右键点击"Table
",选择“Table Layout”
。
-
在”Table Layout”
对话框中, 单击“ Column”标签,然后单击“New”,添加两个新列到表中。
-
Column Details
QUANTITY输入框设置
" Order"按钮列设置
Header Text
Quantity
Footer Text
Component Type
Text Field
Button
Value Expression
text
Order
Horizontal Align
Right
Center
-
修改一些组件的ID, 通过菜单”Windows” ->”Properites” 打开属性窗口.
JSP 组件 | id | 组件类型 |
---|---|---|
PRODUCT_ID | stProductId | Static Text |
QUANTITY | tfQuantity | Text Field |
”Order”按钮 | addOrder | Button |
订单保存在数据库中
-
在page1.jsp
可视设计器中,双击"Order
"按钮,以打开Java
编辑器。在Java
编辑器中,插入点将位于该按钮的addOrder_action()
事件处理程序方法中。
-
源代码编辑器中, 任意位置单击鼠标右键,选择“Enterprise Resource”>“Call Enterprise Bean”。
-
在“Call Enterprise Bean”窗口中,选择“BookshopApp-ejb” -> “PurchaseOrderFacade”,点击完成。
-
这一步骤之后,IDE会在 Page1.java代码中,加入对EJB的引用方法。
“@EJB private PurchaseOrderFacadeLocal purchaseOrderFacade;”
-
修改 Page1.java代码中 方法a
ddOrder_action()
-
代码样例 9: Page1.java 中
a
ddOrder_action()
import bookshop.ejb.PurchaseOrderFacadeLocal; import bookshop.entities.*; ...... @EJB PurchaseOrderFacadeLocal purchaseOrderFacade; public String addOrder_action() { //Get max order number. CachedRowSetDataProvider maxOrder = getSessionBean1().getMaxOrderDataProvider(); maxOrder.refresh(); //Get order fields and save the new order into database PurchaseOrder order = new PurchaseOrder(); order.setOrderNum((Integer) maxOrder.getValue("MAXORDERID")); order.setCustomerId((String)dropDown1.getValue()); order.setProductId((Integer)stProductId.getValue()); order.setQuantity(new Short((String)tfQuantity.getValue())); purchaseOrderFacade.create(order); //Pass the user name to next page getRequestBean1().setCustomerId((String)dropDown1.getValue()); return "case1"; }
注意a
ddOrder_action()
返回的也是"case1
",
因此,这个按钮和"search
"按钮共享同样的导航,
即同样会跳转到OrderList.jsp
页面.
测试
-
右键单击
BookshopApp
项目,选择"Undeploy and Deploy
".
-
在浏览器中输入URL: “http://localhost:8080/BookshopApp-war/”
,选择用户,
输入数量,
点击”Order”
按钮.
在下一个页面,
能够看到新添加的订单信息.
删除订单
-
打开OrderList.jsp
可视设计器。右键点击"Table
",打开“Table Layout”
对话框。
-
单击“Columns”标签,然后单击“New”按钮,添加一个新列到表中。
在“Properties”
窗口中,把“Delete”
按钮的ID
改为“delete”
Column Details | "Delete"按钮列设置 |
---|---|
Header Text | |
Footer Text | |
Component Type | Button |
Value Expression | Delete |
Horizontal Align | Center |
-
在
OrderList.jsp
可视设计器中,双击"Delete
"按钮,以打开Java
编辑器。在Java
编辑器中,插入点将位于该按钮的delete_action()
事件处理程序方法中。
-
代码样例 9: OrderList.java 中
delete_action()
import com.sun.data.provider.RowKey; ...... public String buttonDelete_action() { // TODO: Process the action. Return value is a navigation // case name where null will return to the same page. 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
项目,选择"Undeploy and Deploy
".
-
在浏览器中输入URL: “http://localhost:8080/BookshopApp-war/”
,选择用户,
点击”Search”
按钮.
-
在下一个页面上,
点击”Delete”
按钮.
安装jMaki Plug-in
-
NetBeans IDE中,菜单选择“Tools”>“Plugins”>”。
-
在“Plugins”窗口中,选择“Download”标签,点击“Add Plugins”按钮,在浏览器中选择jMaki在NetBeans的Plugin下载文件“org-netbeans-modules-sun-jmaki.nbm”
-
点击”install”按钮后,会出现“NetBeans IDE Installer”窗口,点击”Next”按钮。
-
在下一个窗口中,选择“I accept the terms in all of the license agreements”,点击”Install”按钮。
-
如果希望Plugin立刻生效,在最后一个窗口中选择“Restart IDE Now”, 点击”Finish”按钮。
-
重新启动NetBeans IDE后,选择菜单“Window”->”Palette”, 可以看到组件面板中已经出现了jMaki
使用AJAX组件Data Table显示信息
-
右键单击
BookshopApp-war
项目,选择"New
"->”Servlet”
-
在“New Servlet”
窗口中,File Name:
输入”ProductService”, package
:bookshop.web,
点击“Finish”
按钮
-
代码样例 9:
ProductService.java
/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package book.web; import java.io.*; import java.net.*; import javax.servlet.*; import javax.servlet.http.*; import javax.ejb.EJB; import bookshop.ejb.*; import bookshop.entities.*; import java.util.List; /** * * @author Sun */ public class ProductService extends HttpServlet { /** * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods. * @param request servlet request * @param response servlet response */ @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(); try { List<Product> list = productFacade.findAll(); out.println("{columns : [" + "{ label : 'Book ID', id : 'productid'}," + "{ label :'Book Name', id : 'productname'}," + "{ label :'Book Price', id : 'purchasecost'}" + "],"); out.println("rows: ["); for (int i = 0; i < list.size(); i++) { Product b = list.get(i); out.print("{ id: '" + b.getProductId() + "', " + "productid: '" + b.getProductId() + "'," + "productname: '" + b.getProductName() + "'," + "purchasecost: '" + b.getPurchaseCost() + "'}"); if (i < list.size() - 1) { out.println(","); } else { out.println(); } } out.println("] }"); } finally { out.close(); } } ......
-
打开BookshopApp-war
项目下的index.jsp.
-
从”palette”
窗口中拖“jMaki Yahoo Data Tabel”
到index.jsp
中,拖动的结果会在项目下的Web Pages/resource
下创建yahoo
目录,包含Data Table
所需要的一些image, html, js, css, json
文件。
-
修改index.jsp
的内容.
-
代码样例 9:
index.jsp
<%@ taglib prefix="a" uri="http://jmaki/v1.0/jsp" %> <%-- Document : index Created on : 2007-11-26, 18:59:58 Author : Sun --%> <%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSP Page</title> </head> <body> <h2>Hello World!</h2> <a:widget name="yahoo.dataTable" service="/ProductService" /> </body> </html>
6. 修改BookshopApp-war
项目下的web.xml, 设置起始页面为index.jsp
设置起始页面为index.jsp
测试
-
右键单击
BookshopApp
项目,选择"Undeploy and Deploy
".
-
在浏览器中输入URL: “http://localhost:8080/BookshopApp-war/”
参考
Http://www.netbeans.org