一直想做一个 EJB3.0 结合 Struts 的例子,前天刚好从网上找到了一个相关的 Tutorial ,于是小试了一把,虽然只是完成了 Tutorial 上的一小点功能,但是感觉还是有必要写下来,免得以后还要再去看别人的Tutorial 。
开发环境:
Eclipse3.2 + WTP1.5 , JBoss 4.0.3SP1 , jboss-EJB-3.0_RC5-PFD,MySQL5.0.16
环境的搭建可以参考我的学习笔记:
EJB 3.0 学习笔记——准备工作 : http://www.blogjava.net/felicity/archive/2006/03/26/37510.html
EJB 3.0 学习笔记—— Entity Bean : http://www.blogjava.net/felicity/archive/2006/05/20/47229.html
在MySQL 中新建数据库ejbstruts,在JBoss的all\deploy下新建ejbstruts-ds.xml,其内容如下:
<?
xml version="1.0" encoding="UTF-8"
?>
<!--
$Id: mysql-ds.xml,v 1.3.2.1 2004/12/01 11:46:00 schrouf Exp $
-->
<!--
Datasource config for MySQL using 3.0.9 available from:
http://www.mysql.com/downloads/api-jdbc-stable.html
-->
<
datasources
>
<
local-tx-datasource
>
<
jndi-name
>
EJBStrutsDS
</
jndi-name
>
<
connection-url
>
jdbc:mysql://localhost:3306/ejbstruts
</
connection-url
>
<
driver-class
>
com.mysql.jdbc.Driver
</
driver-class
>
<
user-name
>
test
</
user-name
>
<
password
></
password
>
<
exception-sorter-class-name
>
org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter
</
exception-sorter-class-name
>
<!--
sql to call when connection is created
<new-connection-sql>some arbitrary sql</new-connection-sql>
-->
<!--
sql to call on an existing pooled connection when it is obtained from pool
<check-valid-connection-sql>some arbitrary sql</check-valid-connection-sql>
-->
<!--
corresponding type-mapping in the standardjbosscmp-jdbc.xml (optional)
-->
<
metadata
>
<
type-mapping
>
mySQL
</
type-mapping
>
</
metadata
>
</
local-tx-datasource
>
</
datasources
>
新建工程:
最后的程序会打包成一个EAR部署到JBoss,所以在Eclipse中创建三个新的工程:
1、EAR Project:EJBStruts
选好 Target Runtiem为 JBoss后Finish。
2、Java EJB3 Project: EJBStrutsEJB
由于WTP1.5还不支持EJB3.0的直接创建,这里新建的是一个普通的Java Project,之后会用ant来创建ejb jar。
由于是普通的Java Project,之后直接Finish好了。
3、 WEB Project:EJBStrutsWeb
这里可以将工程添加到前面建好的EAR中。
EJB模块
向EJBStrutsEJB工程中导入User Library:EJB3_JBoss
新建两个EJB Entities:Book 和Customer
/**
* Book.java
*/
package
com.lzy.library.domain;
import
java.io.Serializable;
import
javax.persistence.Column;
import
javax.persistence.Entity;
import
javax.persistence.GeneratedValue;
import
javax.persistence.GenerationType;
import
javax.persistence.Id;
import
javax.persistence.JoinColumn;
import
javax.persistence.ManyToOne;
import
javax.persistence.Table;
@Entity
@Table(name
=
"
BOOK
"
)
public
class
Book
implements
Serializable {
/**
*
*/
private
static
final
long
serialVersionUID
=
1L
;
private
Integer id;
private
String title;
private
String author;
private
Customer customer;
public
Book() {
super
();
}
public
Book(Integer id, String title, String author) {
super
();
this
.id
=
id;
this
.title
=
title;
this
.author
=
author;
}
@Column(name
=
"
AUTHOR
"
)
public
String getAuthor() {
return
author;
}
public
void
setAuthor(String author) {
this
.author
=
author;
}
@Id
@GeneratedValue(strategy
=
GenerationType.AUTO)
@Column(name
=
"
ID
"
)
public
Integer getId() {
return
id;
}
public
void
setId(Integer id) {
this
.id
=
id;
}
@Column(name
=
"
TITLE
"
)
public
String getTitle() {
return
title;
}
public
void
setTitle(String title) {
this
.title
=
title;
}
@ManyToOne
@JoinColumn(name
=
"
CUSTOMER_ID
"
)
public
Customer getCustomer() {
return
customer;
}
public
void
setCustomer(Customer customer) {
this
.customer
=
customer;
}
@Override
public
String toString() {
return
"
Book:
"
+
getId()
+
"
Title
"
+
getTitle()
+
"
Author
"
+
getAuthor();
}
}
/** */
/**
* Customer.java
*/
package
com.lzy.library.domain;
import
java.io.Serializable;
import
java.util.ArrayList;
import
java.util.List;
import
javax.persistence.CascadeType;
import
javax.persistence.Column;
import
javax.persistence.Entity;
import
javax.persistence.FetchType;
import
javax.persistence.GeneratedValue;
import
javax.persistence.GenerationType;
import
javax.persistence.Id;
import
javax.persistence.OneToMany;
import
javax.persistence.Table;
/** */
/**
*
@author
rouserli
*
*/
@Entity
@Table(name
=
"
CUSTOMER
"
)
public
class
Customer
implements
Serializable
{
/** */
/**
*
*/
private
static
final
long
serialVersionUID
=
1L
;
private
Integer id;
private
String name;
private
List books
=
new
ArrayList();
public
Customer()
{
super
();
//
TODO Auto-generated constructor stub
}
public
Customer(Integer id, String name)
{
super
();
this
.id
=
id;
this
.name
=
name;
}
@Id
@GeneratedValue(strategy
=
GenerationType.AUTO)
@Column(name
=
"
ID
"
)
public
Integer getId()
{
return
id;
}
public
void
setId(Integer id)
{
this
.id
=
id;
}
@Column(name
=
"
NAME
"
)
public
String getName()
{
return
name;
}
public
void
setName(String name)
{
this
.name
=
name;
}
@OneToMany(cascade
=
CascadeType.ALL, fetch
=
FetchType.EAGER, mappedBy
=
"
customer
"
, targetEntity
=
Book.
class
)
public
List getBooks()
{
return
books;
}
public
void
setBooks(List books)
{
this
.books
=
books;
}
@Override
public
String toString()
{
return
"
Customer:
"
+
getId()
+
"
Name
"
+
getName();
}
}
在工程下新建
META-INF目录,该目录下新建persistence.xml文件。
<?
xml version="1.0" encoding="UTF-8"
?>
<
persistence
>
<
persistence-unit
name
="test"
>
<
jta-data-source
>
java:/EJBStrutsDS
</
jta-data-source
>
<
properties
>
<
property
name
="hibernate.dialect"
value
="org.hibernate.dialect.MySQLDialect"
/>
<
property
name
="hibernate.hbm2ddl.auto"
value
="update"
/>
</
properties
>
</
persistence-unit
>
</
persistence
>
然后新建DAO接口BookDao(Local)和CustomerDao(Local),以及各自的实现BookDaoImpl(Stateless)和CustomerDaoImpl(Stateless),在后面的Web工程中,将通过这两个DAO接口进行数据库操作。由于这部分可供参考的例子很多,略去源码。
新建文件builder.xml
<?
xml version="1.0"
?>
<!--
=======================================================================
-->
<!--
JBoss build file
-->
<!--
=======================================================================
-->
<
project
name
="JBoss"
default
="ejbjar"
basedir
="."
>
<
property
file
="../local.properties"
/>
<
property
environment
="env"
/>
<
property
name
="src.dir"
value
="${basedir}/src"
/>
<
property
name
="jboss.home"
value
="E:/Programming/Servers/jboss-4.0.3SP1/"
/>
<
property
name
="jboss.server.config"
value
="all"
/>
<
property
name
="build.dir"
value
="${basedir}/build"
/>
<
property
name
="build.classes.dir"
value
="${build.dir}/classes"
/>
<!--
Build classpath
-->
<
path
id
="classpath"
>
<!--
So that we can get jndi.properties for InitialContext
-->
<
pathelement
location
="${basedir}"
/>
<
fileset
dir
="${jboss.home}/lib"
>
<
include
name
="**/*.jar"
/>
</
fileset
>
<
fileset
dir
="${jboss.home}/server/${jboss.server.config}/lib"
>
<
include
name
="**/*.jar"
/>
</
fileset
>
<
fileset
dir
="${jboss.home}/server/${jboss.server.config}/deploy/ejb3.deployer"
>
<
include
name
="*.jar"
/>
</
fileset
>
<
fileset
dir
="${jboss.home}/server/${jboss.server.config}/deploy/jboss-aop-jdk50.deployer"
>
<
include
name
="*.jar"
/>
</
fileset
>
<
pathelement
location
="${build.classes.dir}"
/>
</
path
>
<
property
name
="build.classpath"
refid
="classpath"
/>
<!--
===================================================================
-->
<!--
Prepares the build directory
-->
<!--
===================================================================
-->
<
target
name
="prepare"
>
<
mkdir
dir
="${build.dir}"
/>
<
mkdir
dir
="${build.classes.dir}"
/>
</
target
>
<!--
===================================================================
-->
<!--
Compiles the source code
-->
<!--
===================================================================
-->
<
target
name
="compile"
depends
="prepare"
>
<
javac
srcdir
="${src.dir}"
destdir
="${build.classes.dir}"
debug
="on"
deprecation
="on"
optimize
="off"
includes
="**"
>
<
classpath
refid
="classpath"
/>
</
javac
>
</
target
>
<
target
name
="ejbjar"
depends
="compile"
>
<
jar
jarfile
="build/EJBStrutsEJB.jar"
>
<
fileset
dir
="${build.classes.dir}"
>
<
include
name
="**/*.class"
/>
</
fileset
>
<
fileset
dir
="."
>
<
include
name
="META-INF/persistence.xml"
/>
</
fileset
>
</
jar
>
<
copy
file
="build/EJBStrutsEJB.jar"
todir
="${jboss.home}/server/${jboss.server.config}/deploy"
/>
</
target
>
<
target
name
="clean"
>
<
delete
dir
="${build.dir}"
/>
<
delete
file
="${jboss.home}/server/${jboss.server.config}/deploy/EJBStrutsEJB.jar"
/>
</
target
>
</
project
>
Ant build后将可以看到EJBStrutsEJB.jar。
Web(struts)模块:
这部分更加简单,完成一个最简单的功能:向数据库中添加测试数据。
只需要在相应的Action类里得到DAO,然后操作数据库。
首先将EJBStrutsEJB中的EJBStrutsEJB.jar添加到工程的build path 中:
然后创建相应的Action类:
/**
/**
* Common.java
*/
package
com.lzy.library.web.action;
/**
*
@author
rouserli
*
*/
public
class
Common {
private
Common(){
}
public
static
final
String JNDI_PREFIX
=
"
LearnEJB3/
"
;
//
forward used as success
public
static
final
String SUCCESS
=
"
success
"
;
//
forward used for failure
public
static
final
String FAILURE
=
"
failure
"
;
//
forward used for self
public
static
final
String SELF
=
"
self
"
;
//
session key for customer
public
static
final
String CUSTOMER_KEY
=
"
customer_key
"
;
//
session key for cart
public
static
final
String CART_KEY
=
"
cart
"
;
}
/**
*
*/
package
com.lzy.library.web.action;
import
java.util.Random;
import
javax.naming.Context;
import
javax.naming.InitialContext;
import
javax.naming.NamingException;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
org.apache.struts.action.Action;
import
org.apache.struts.action.ActionForm;
import
org.apache.struts.action.ActionForward;
import
org.apache.struts.action.ActionMapping;
import
com.lzy.library.dao.BookDao;
import
com.lzy.library.dao.CustomerDao;
import
com.lzy.library.dao.impl.BookDaoImpl;
import
com.lzy.library.dao.impl.CustomerDaoImpl;
import
com.lzy.library.domain.Book;
import
com.lzy.library.domain.Customer;
/**
*
@author
rouserli
*
*/
public
class
CreateSampleDataAction
extends
Action {
@Override
/**
* Method execute
*
*
@param
mapping
*
@param
form
*
@param
request
*
@param
response
*
@return
ActionForward
*/
public
ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
System.out.println(
"
CreateSampleData
"
);
BookDao bookDao;
CustomerDao customerDao;
Random r
=
new
Random();
try
{
Context context
=
new
InitialContext();
System.out.println(
"
Look up BookDaoImpl:
"
+
BookDaoImpl.LocalJNDIName);
System.out.println(
"
Look up CustomerDaoImpl:
"
+
CustomerDaoImpl.LocalJNDIName);
bookDao
=
(BookDao) context.lookup(
"
EJBStruts/
"
+
BookDaoImpl.LocalJNDIName);
customerDao
=
(CustomerDao) context
.lookup(
"
EJBStruts/
"
+
CustomerDaoImpl.LocalJNDIName);
}
catch
(NamingException e) {
e.printStackTrace();
throw
new
RuntimeException(e);
}
System.out.println(
"
to return from action
"
);
Book book
=
new
Book(
null
,
"
EJB 3 Developer
"
+
r.nextInt(
100
),
"
Sebastian
"
);
bookDao.save(book);
Customer customer
=
new
Customer(
null
,
"
Sebastian
"
+
r.nextInt(
100
));
customerDao.save(customer);
return
mapping.findForward(Common.SUCCESS);
}
}
在src文件夹中新建
jndi.properties:
java.naming.factory.initial
=
org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs
=
org.jboss.naming:org.jnp.interfaces
java.naming.provider.url
=
localhost
页面文件:
welcom.jsp
<%
@ page language
=
"
java
"
contentType
=
"
text/html; charset=GBK
"
pageEncoding
=
"
GBK
"
%>
<%
@ taglib uri
=
"
http://struts.apache.org/tags-bean
"
prefix
=
"
bean
"
%>
<%
@ taglib uri
=
"
http://struts.apache.org/tags-html
"
prefix
=
"
html
"
%>
<%
@ taglib uri
=
"
http://struts.apache.org/tags-tiles
"
prefix
=
"
tiles
"
%>
<!
DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
>
<
html
>
<
head
>
<
meta
http-equiv
="Content-Type"
content
="text/html; charset=GBK"
>
<
title
>
navigation
</
title
>
</
head
>
<
body
>
<
table
>
<
TR
>
<
TD
><
html:link
action
="createSampleData"
>
Create Sample Data
</
html:link
>
</
TD
>
</
TR
>
</
table
>
</
body
>
</
html
>
EAR工程打包、部署、运行:
修改application.xml如下:
<?
xml version="1.0" encoding="UTF-8"
?>
<
application
id
="Application_ID"
version
="1.4"
xmlns
="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation
="http://java.sun.com/xml/ns/j2eehttp://java.sun.com/xml/ns/j2ee/application_1_4.xsd"
>
<
display-name
>
EJBStruts
</
display-name
>
<
module
id
="WebModule_1155011213937"
>
<
web
>
<
web-uri
>
EJBStrutsWeb.war
</
web-uri
>
<
context-root
>
EJBStrutsWeb
</
context-root
>
</
web
>
</
module
>
<
module
>
<
ejb
>
EJBStrutsEJB.jar
</
ejb
>
</
module
>
</
application
>
确认EAR工程的模块依赖无误后Export出ear包。
将导出的EJBStruts.ear文件拷到JBoss的all/deploy目录下,以all模式启动JBoss。
确认启动无误之后可以在你的浏览器中打开welcom.jsp,点击链接,如果执行正确,就会发现数据已经写入数据库中。
Reference:
EJB 3 Struts Framework Integration Tutorial, by Sebastian Hennebrueder
OReilly.Enterprise.JavaBeans.3.0.5th.Edition, by Bill Burke , Richard Monson-Haefel