一直想做一个 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
?
?
?
?