Java EE 5 是 Java 企业级应用规范的最新标准,它在以往版本的基础上进行了大范围的改进,吸取了开源领域广泛使用的技术(例如 POJO,IoC),降低了 Java EE 的学习难度,简化了企业级应用程序的开发,提高了开发效率。
以下是 Java EE 5 中引入的五个比较重要的技术:
- Java Annotation 不是 Java EE 5 中的技术,它是 Java 5 的一个新的特性。但是在 Java EE 5 中大量的使用了 Annotation,因为它的使用,极大的简化了 Java EE 应用程序的开发和维护。
- Java Server Faces (JSF)是对 JSP 技术的一种扩展和增强,它已经存在了一段时间,但并没有被包含在 J2EE 规范中,用户需要在他们的 Web 应用中包含 JSF 的 jar 文件来支持 JSF 技术。Java EE 5 中包含了最新的 JSF 1.2 规范,从而在 WAS CE v2.1 上开发 JSF的应用也变得更加容易。
- Java Persistence API (JPA)是用来代替 J2EE 中 Entity Bean 的一种技术规范。在 Java EE 5 中,Entity Bean 规范没有进行任何更新,旧的 Entity Bean 在 Java EE 5 中还被支持,但新添加的 JPA 是将来 Java EE 中持久化技术的方向。使用 JPA 开发数据库应用也变得更加简单和容易。
- Enterprise Java Bean (EJB) 3.0 是对 EJB 技术的一次比较大的改动。EJB 3.0 充分利用了 Java Annotation,提供了一个新的 EJB 编程模型,从而简化了 EJB 应用程序的开发。
- JAX-WS 2.0 是 JAX-RPC 1.1 的一个后继版本,JAX-RPC 不会再有新的版本,而 JAX-WS 2.0 会成为 Java EE 5 中实现 Web Service 的技术。
本文将通过开发一个网上商店的具体示例,向您展示如何在 WAS CE 中使用以上技术。
为了在 WAS CE v2.1 中展示以上所提到的新技术,我们假设了一个网上商店:Ollivanders (Harry Potter 的魔法世界中最好的魔杖商店),简称 OlliShop。OlliShop 提供了简单的 Web 界面,用户可以用此 Web 界面注册、登录和购买魔杖;另外 OlliShop 向第三方集成商提供了 WebService 接口,可以通过 SOAP 协议来调用 OlliShop 的服务。您可以下载本例的源代码。
网上商店的架构如图 1 所示:
图 1. OlliShop 的架构图
OlliShop 由 5 个功能模块组成:
- ShopWEB 是 OlliShop 的用户界面,用户只能通过浏览器来访问此模块。ShopWEB 模块使用了 JSF 技术。
- ShopWS 是 OlliShop 的 Web Service 接口,它提供了其它应用程序通过 Web Service 的方式访问 OlliShop 的服务。此模块使用了 JAX-WS 技术。
- ShopUtil 是一个工具包,包含一些公用的工具类以供其它模块使用。
- ShopEJB 是业务实现模块,主要包括一个无状态 Session Bean,供 ShopWEB 和 ShopWS 调用。此模块使用了 EJB 3.0 技术。
- ShopJPA 是数据库访问模块,它通过 ORM 机制把对数据库的操作转换成对对象的操作。此模块使用了 JPA 技术。
WAS CE 作为一个开源的应用服务器,选择一个免费且强大的开发工具是很必要的,Eclipse 就是一个不错的选择。WAS CE 提供了一个 Eclipse 插件,可以通过此插件来管理 WAS CE 应用服务器,开发、部署和调试 Java EE 的应用,再配合 Eclipse 中的 WTP(Web Tools Platform)插件,对于一个小规模的应用,这样的 IDE 已经可以胜任。
本文使用的 Eclipse 环境如下:
- Eclipse 3.4
- Eclipse WTP 3.0M2
- WAS CE Server adapter 2.1,此插件可以从以下网址下载:http://public.dhe.ibm.com/software/websphere/wasce/updates/
在 Eclipse 的 J2EE 视图中的 Servers view 处创建 WAS CE 服务器,如图 2 所示。
图2. Eclipse中的WAS CE Server
现在我们开发 Java EE 应用程序的环境已经准备好了,可以开始 OlliShop 应用的开发了。OlliShop 包含了多个模块,是一个典型的 EAR 应用程序,整个 OlliShop 的工程视图如图 3,它包括 6 个工程。在后面的描述中我们将会具体介绍每一个工程。
图 3. OlliShop 中包含的工程
通过 Eclipse 中的 "Enterprise Application Project" 向导创建一个 EAR 工程。需要注意的是,创建工程时需要选择上面创建的 IBM WAS CE v2.1 作为 Target Runtime,如图 4 所示。以下的所有工程除了 ShopUtil 外都需要 IBM WAS CE v2.1 作为 Target Runtime。
图 4. 创建 ShopEAR 工程
此工程创建后会自动在 EarContent\META-INF\ 目录下生成 WAS CE 的部署计划:geronimo-application.xml。双击此文件可以打开此部署计划的编辑界面,通过此编辑界面可以很容易的操作此部署计划。
通过 Eclipse 中的 ”JPA Project” 向导创建 ShopJPA 工程。创建过程中可以把此工程加入到上面创建的 ShopEAR 工程中。此工程创建后,Eclipse 会转换到 JPA 视图。此时我们需要使用数据库了,因此我们需要先创建数据库。
WAS CE 中默认的内置数据库为 Derby,我们的 OlliShop 应用就是使用了此数据库。通过J2EE 视图中的 Servers view,可以启动 WAS CE。通过 http://localhost:8080/console/
进入 WAS CE 的管理控制台,默认的用户名/口令为 system/manager。通过此控制台可以管理Derby 数据库,单击左边菜单栏中的 "DB Manager" 进入数据库管理界面,创建名为 "shop" 的数据库,然后可以使用以下脚本创建所需要的表:
清单 1. 创建数据库脚本
CREATE TABLE Users ( ID INTEGER NOT NULL, UserName VARCHAR(250) NOT NULL, Password VARCHAR(250) NOT NULL ); CREATE TABLE Goods ( ID INTEGER NOT NULL, Name VARCHAR(250) NOT NULL, Price DECIMAL(14, 2) NOT NULL, Quantity DOUBLE NOT NULL ); CREATE INDEX Users_ID ON Users(ID); CREATE INDEX Goods_ID ON Goods(ID); |
JPA 需要通过数据源才能访问到相应的数据库,在 WAS CE 中有两种方式创建数据源:通过管理控制台创建和通过部署计划创建。在这里我们使用第二种方式,所以需要修改在 ShopEAR 中的部署计划:geroniom-application.xml。
在 geronimo-application.xml 中添加以下代码:
清单2. geronimo-application.xml
<ext-module> <connector>ShopDataSource</connector> <external-path xmlns:dep="http://geronimo./xml/ns/deployment-1.2"> <dep:groupId>org.tranql</dep:groupId> <dep:artifactId>tranql-connector-derby-embed-local</dep:artifactId> <dep:type>rar</dep:type> </external-path> <connector xmlns="http://geronimo./xml/ns/j2ee/connector-1.2"> <resourceadapter> <outbound-resourceadapter> <connection-definition> <connectionfactory-interface> javax.sql.DataSource </connectionfactory-interface> <connectiondefinition-instance> <name>jdbc/ShopDataSource</name> <config-property-setting name="UserName"> </config-property-setting> <config-property-setting name="Password"> </config-property-setting> <config-property-setting name="DatabaseName"> shop </config-property-setting> <config-property-setting name="CreateDatabase"> true </config-property-setting> <connectionmanager> <single-pool> <max-size>100</max-size> <min-size>0</min-size> <blocking-timeout-milliseconds> 5000 </blocking-timeout-milliseconds> <idle-timeout-minutes>30</idle-timeout-minutes> <match-one/> </single-pool> </connectionmanager> </connectiondefinition-instance> </connection-definition> </outbound-resourceadapter> </resourceadapter>> </connector> </ext-module> |
从以上代码可以看出此数据源指定的数据库为 shop,创建的数据源的 JNDI 的名字为jdbc/ShopDataSource。
Eclipse 提供了一个创建 JPA Entity Bean 的工具,此工具能够根据数据库中表的设置创建出相应的 Entity Bean。为了使用此工具,需要先在 Eclipse 中连接到 Derby 数据库,在 JPA 视图的 Data Source Explorer 中创建到 Derby 的连接。步骤如下:
1. 在 "Database" 的右键菜单中选择 "New …"
2. 选择 “Generic JDBC Connection”
3. 输入连接的名字:Derby
4. 选择 “Derby Client JDBC Driver”,Derby JDBC Driver位于:%WASCE_HOME%\repository\org\apache\derby\derbyclient\10.2.2.0\derbyclient-10.2.2.0.jar
。输入以下连接属性:
Database:shop
URL:jdbc:derby://localhost:1527/shop;create=true
User Name:user
Password:app
5. 连接刚创建的 Derby。
现在可以通过 Derby 连接创建相应的 Entity Bean 了。在 shop 数据库中只有两个表:users 和 goods。我们先创建一个类 com.ibm.wasce.shop.entity.User,此时在 JPA 视图中就可以把此类映射到数据库中的表 users,如图5所示。
图 5. User 类映射到表 users
在 User类 中添加 3 个属性:id、userName、password,然后把它们映射到 users 表中的字段,如图 6 所示。
图6. 映射属性 id 到表 users 中的字段 id
用户登录时,需要从数据库中根据用户输入的用户名查询该用户来验证用户名和密码。在传统的应用中,我们需要从数据源中得到 Connection,然后执行 SQL 语句,从返回的数据集中获得数据,再生产相应的 User 对象。在 EJB 3.0 中,这项工作已经大大简化,主要是因为使用了 Annotation NamedQueries 和 EJB QL。通过 NamedQueries,只需要再声明一个 EJB QL,就可以得到相应的 User 对象,开发人员不再需要关心数据库连接和数据转换等繁琐的事情。EJB QL 是和 SQL 很像的一种语言,只是它要操作的不是数据库中的表,而是 JPA Entity Bean。
最终生成的 User 类如下:
清单3. 生成 JPA 实体 Bean
@NamedQueries ( { @NamedQuery ( name = "getUserByName", query = "select u from User u where u.userName= :name" ) }) @Entity @Table(name="USERS", schema = "APP") public class User { @Id @GeneratedValue private Integer id; private String userName; private String password; // 以下的setter/getter方法省略 |
通过以上的方式,我们创建了与表 goods 相对应的 JPA Entity Bean。
接下来,我们将通过 Eclipse 中的 “EJB Project” 向导创建 ShopEJB 工程,同时把新创建的工程加入到 ShopEAR 中。
此工程中的 EJB 采用 EJB 3.0 的方式开发。在传统的EJB编程模型中,每一个Bean需要两个接口和一个类来组成:Remote(或Local)接口、Home 接口和 Bean 实现类,而且这三个类之间需要通过某种编码约定来规范,在部署时再由 EJB 容器生产一些魔术代码(Magic Codes)把它们之间的调用关系连起来。而在 EJB 3.0 中的实现则显得更加简单和直接,一个 EJB 只需要一个接口和一个类:Remote(或 Local)接口和实现 Remote(或 Local)接口的类。另外一个区别是在 EJB 3.0 中部署描述符(ejb-jar.xml)也不再是必须的了,我们可以通过 Annotation 的方式来定义这些元数据。
以下是 ShopBean 的 Local 接口,它是一个普通的 Java 接口。如果是 Remote 接口,则需要加上 Annotation @Remote。
清单 4. ShopBean 的 Local 接口
public interface ShopBean { public boolean login( String name, String password ); public List listGoods(); public Good getGoodById( int id ); } |
以下是 ShopBean 的实现类。在此类中,唯一能感觉到它和 EJB 相关的地方就是 @Stateless
,其它的地方和普通的 Java 类没有区别。此类主要用来实现操作在 ShopJPA 中开发的 Entity Bean。EntityManager 是 JPA 中最重要的一个接口,应用程序主要通过它来添加、修改和查询 Entity Bean。通过 Annotation @PersistenceContext
,WAS CE 中的 EJB 容器会把一个 EntityManager 的实例赋给此类中的em对象,这就是在 EJB 3.0 中被广泛使用的依赖注入(Dependency Injection)的方法。在这个类中,也用到了在 ShopJPA 中定义的 NamedQuery。
清单 5. ShopBean 的实现
@Stateless public class ShopBeanImpl implements ShopBean { @PersistenceContext private EntityManager em; public Good getGoodById(int id) { Query query = em.createNamedQuery( "getGoodByID" ); query.setParameter("id", id); return (Good)query.getSingleResult(); } public List listGoods() { Query query = em.createNamedQuery( "getAllGoods" ); return query.getResultList(); } public boolean login(String name, String password) { try { Query query = em.createNamedQuery( "getUserByName" ); query.setParameter( "name", name ); User user = (User)query.getSingleResult(); return user != null && user.getPassword().equals( password ); } catch ( Exception e ) { return false; } } |
通过 Eclipse 中的 "Java Project" 向导创建 ShopUtil 工程。可以在 ShopEAR 工程的属性管理页面中,把 ShopUtil 工程加入到 ShopEAR 中。
此工程提供了 ShopWEB 和 ShopWS 访问 EJB 的功能,而不需要在两个 Web 工程中分别定义。它使用 JNDI 的方式访问 EJB,如清单 6 所示:
清单 6. 使用 JNDI 访问 EJB
private EJBLocator() { try { InitialContext rootContext = new InitialContext(); shopbean = (ShopBean)rootContext.lookup( "java:comp/env/ejb/shopbean" ); } catch ( NamingException ne ) { ne.printStackTrace(); } } |
接下来,我们将创建两个 Web 工程。在创建的两个 Web 工程中需要进行以下设置才可以使用:
- 在 Web 工程的属性中:"Java Build Path" -> "Projects" 中添加 ShopUtil 工程。
- 添加以下一行到 Web 工程的文件:WebContent\META-INF\ MANIFEST.MF;Class-Path: ShopUtil.jar
在创建此工程前,需要先根据 WTP 的文档来设置 Java Server Faces,WAS CE v2.1 提供了JSF 所需要的以下两个 Jar 文件:
- %WASCE_HOME%\repository\org\apache\myfaces\core\myfaces-api\1.2.0\myfaces-api-1.2.0.jar
- %WASCE_HOME%\repository\org\apache\myfaces\core\myfaces-impl\1.2.0\myfaces-impl-1.2.0.jar
设置完 JSF 后,通过 Eclipse 中的 “Dynamic Web Project” 向导创建 ShopWEB 工程,Configurations-> JavaServer Faces v1.2 Project,同时把新创建的工程加入到 ShopEAR 中。
新生成的工程中会包含 JSF 的配置文件:faces-config.xml,双击此文件可打开 JSF 配置编辑器,如图 7 所示。
图 7. faces-config.xml 的编辑器
通过此编辑器中的 ManageBean 页面,可以生成 JSF 中的 Managed Bean。在本例中,有两个Managed Bean:GoodsBean 和 LoginBean。
WST 还提供了一个 JSF 页面编辑器,可以进行可视化的开发。在本例中,有两个页面:一个登录页面和一个显示商品列表的页面。其中登录页面的编辑如图 8 所示。
图 8. JSF 的可视化编辑页面
本例中的业务逻辑是用户正确登录后会自动转到商品列表页面,否则将返回到登录页面。这种页面跳转的逻辑也可以通过可视化的方式来进行设置,如图 9 所示。
图 9. 页面跳转逻辑编辑页面
通过 Eclipse 中的 "EJB Project" 向导创建 ShopWS 工程,同时把新创建的工程加入到ShopEAR 中。
通过 JAX-WS 的方式来开发 Web Service 简化了很多工作。在本例中,我们开发了一个通过商品编号来查询商品价格的 Web Service。此 Service 只需要使用一个接口和一个实现类,在部署时,WAS CE 会根据接口和类中的 Annotation 来生成相应的 WSDL 文件。
以下是此 Service 的接口,使用了 Annotation @WebService
。
清单 7. ShopService 接口
@WebService(name="ShopServicePortType", targetNamespace = "http://shop.wasce.ibm.com") public interface ShopService { public double getPriceById( int goodsId ); } |
以下是此 Service 的实现类:
清单 8. ShopService 的实现
@WebService(serviceName = "ShopService", portName="ShopServicePort", endpointInterface = "com.ibm.wasce.shop.ws.ShopService", targetNamespace = "http://shop.wasce.ibm.com") public class ShopServiceImpl implements ShopService { public double getPriceById( int goodsId ) { ShopBean shopbean = EJBLocator.getInstance().getShopBean(); Good good = shopbean.getGoodById(goodsId); return 20; } } |
以上定义的 Web Service 需要通过 Servlet 的方式发布,所以需要在 web.xml 中进行以下配置:
清单 9. 在 web.xml 中配置 ShopService
<servlet> <display-name>ShopService</display-name> <servlet-name>ShopService</servlet-name> <servlet-class> com.ibm.wasce.shop.ws.ShopServiceImpl </servlet-class> </servlet> <servlet-mapping> <servlet-name>ShopService</servlet-name> <url-pattern>/shopservice</url-pattern> </servlet-mapping> |
虽然类 com.ibm.wasce.shop.ws.ShopServiceImpl 不是一个 Servlet,它没有继承javax.servlet.http.HttpServlet,但是在部署的时候,WAS CE 的部署程序会对 ShopServiceImpl进行解析,并且生成一个 Servlet 来包装 ShopServiceImpl,这样就可以通过地址 /shopservice来访问到此 Web Service。
也可以通过 JAX-WS 的方式来调用上面生成的 Web Service,代码如下:
清单 10. 调用 ShopService
public static double getPriceById( int goodsId) throws Exception { URL url = new URL("http://localhost:8080/ShopWS/shopservice?wsdl"); QName qname = new QName("http://shop.wasce.ibm.com", "ShopService"); Service service = Service.create(url, qname); ShopService shopservice = (ShopService)service.getPort(ShopService.class); double price = shopservice.getPriceById( goodsId ); return price; } |
在 Eclipse 中开发完以上模块后,就可以部署此应用。我们可以通过两种方式来部署:通过Eclipse 部署或者从 Eclipse 中导出 EAR 后通过命令行部署。
第一种方式:通过 Eclipse 部署
- 在 Eclipse 中的 Server 视图,右击 WASCE Server,选择Add and Remove Projects ...
- 添加 ShopEAR 到 Configured projects 列表中
- 点击 Finish
第二种方式:通过命令行部署
- 右击 ShopEAR 工程,选择 Export
- 选择“Java EE”-> EAR file
- 指定要保存的目录和文件名,例如 d:\temp\ShopEAR.ear
- 用以下命令部署导出的 ear 文件
%WASCE_HOME%\bin\deploy --username system --password manager deploy d:\temp\ShopEAR.ear
部署此应用后,可以通过 http://localhost:8080/ShopWEB/
来访问 OlliShop 的主页,默认的用户名/密码为 user1/user1
对于 Web Service,可以通过 http://localhost:8080/ShopWS/shopservice?wsdl
来访问 shopservice的 WSDL 文件,可以通过http://localhost:8080/ShopWS/invokeshopservice.jsp
来调用此 Web Service。
WAS CE v2.1 作为一款免费的 Java EE 5 应用服务器,结合 Eclipse 强大的 WST 工具,为广大开发人员提供了快速的开发环境,也为中小型企业实践 Java EE 5 的应用提供了一个很好的平台。
描述 | 名字 | 大小 | 下载方法 |
---|---|---|---|
代码示例 | OlliShop.zip | 49 KB | HTTP |
学习
- WebSphere Application Server Community Edition V2.1 中的新增功能:本文主要讲述了 WebSphere Application Server Community Edition V2.1 中的新增功能,包括使用 Gshell 执行 Geronimo 命令、在您自己的服务器集基础上创建多个服务器组装,以及通过专家模式和新的 Monitoring Portlet 完全控制服务器的能力。
- 从 Apache Tomcat Version 6.0 迁移到 WAS CE V2.1 :本文将逐步地指导您将一个应用程序部署到 Tomcat 6.0,然后迁移代码并将其部署到 WebSphere Application Server Community Edition V2.1。并通过该示例应用程序突出说明了这两种实现之间的一些显著差异。
- 使用 WAS CE 开发 JPA 应用程序:本教程将向您介绍如何用 JPA 开发 WAS CE 目标平台下的 Java EE 5 应用。本教程通过一个示例应用程序的开发过程,将带您了解如何创建 JPA 项目和持久生成类,如何配置持久单元以及如何部署和运行 Web 应用程序。
- WAS CE 产品文档:本网站向您提供了 WAS CE 不同版本的产品帮助文档。
- Eclipse 网站:本网站向您提供了 开源开发工具 Eclipse 最新。
- Geronimo 专题:为您提供了 Apache Geronimo 相关的技术文章、教程、下载等资源。
- WAS CE 专栏:为您提供了开源应用服务器 WAS CE 相关的技术文章、教程、下载等资源。
获得产品和技术