参考文献:
myeclipse+jboss开发EJB3.0之实体Bean
一. 配置
Jboss有一个默认的数据源DefaultDS,他使用Jboss内置的HSQLDB数据库。实际应用中你可能使用不同的数据库,如MySql、MsSqlServer、Oracle等。各种数据库的数据源配置模版你可以在[Jboss_home]\docs\examples\jca 目录中找到,默认名称为:数据库名+ -ds.xml 。不管你使用那种数据库都需要把他的驱动类Jar 包放置在[Jboss_home]\server\all\lib 目录下,放置后需要启动Jboss服务器。前一篇博客有提到相关内容: JBoss中配置数据源出现错误:“Failed to register driver for: com.mysql.jdbc.Driver”的解决方法下面介绍Mysql的数据源配置,数据源配置文件的取名格式必须为 xxx–ds.xml ,如:mysql-ds.xml ,mssqlserver-ds.xml,oracle-ds.xml 。 数据源文件配置好后需要放置在[jboss_home]/server/config-name/deploy目录下,我现在采用的配置名为:default,所以路径为[jboss_home]/server/default/deploy目录下面定义一个名为MySqlDS的Mysql数据源,连接数据库为ejb,数据库登录用户名为root,密码为root,数据库驱动类为com.mysql.jdbc.Driver。大家只需修改数据库名及登录用户名密码就可以直接使用。
mysql-ds.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- $Id: mysql-ds.xml 41017 2006-02-07 14:26:14Z acoliver $ -->
<!-- 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>MySqlDS</jndi-name>
<connection-url>jdbc:mysql://localhost:3306/ejb?useUnicode=true&characterEncoding=UTF-8</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<user-name>root</user-name>
<password>root</password>
<exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
<!-- should only be used on drivers after 3.22.1 with "ping" support
<valid-connection-checker-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLValidConnectionChecker</valid-connection-checker-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 - MySQLValidConnectionChecker is preferred for newer drivers
<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>
二. 开发实体bean
开发前先介绍需要映射的数据库表:person注意:在这里并没有在数据库中建表,表是在发布ejb这个jar包的时候创建的。
Person.java
package edu.sjtu.erp.ejbstudy.bean;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@SuppressWarnings("serial")
@Entity
@Table(name = "Person")
public class Person implements Serializable {
private Integer personid;
private String name;
private boolean sex;
private Short age;
private Date birthday;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public Integer getPersonid() {
return personid;
}
public void setPersonid(Integer personid) {
this.personid = personid;
}
@Column(nullable=false,length=32)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Column(nullable=false)
public boolean getSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
@Column(nullable=false)
public Short getAge() {
return age;
}
public void setAge(Short age) {
this.age = age;
}
@Temporal(value=TemporalType.DATE)
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
为了使用上面的实体Bean,我们定义一个Session Bean作为他的使用者。下面是Session Bean 的业务接,他定义了两个业务方法insertPerson和getPersonNameByID,insertPerson用作添加一个Person,getPersonNameByID 根据personid获取人员的姓名。
package edu.sjtu.erp.ejbstudy.dao;
import java.util.Date;
public interface PersonDAO {
public boolean insertPerson(String name,boolean sex,Short age,Date birthday);
public String getPersonNameById(int personid);
}
下面是Session Bean的实现
package edu.sjtu.erp.ejbstudy.impl;
import java.util.Date;
import java.util.List;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import edu.sjtu.erp.ejbstudy.bean.Person;
import edu.sjtu.erp.ejbstudy.dao.PersonDAO;
@Stateless
@Remote(PersonDAO.class)
public class PersonDAOBean implements PersonDAO {
@PersistenceContext
protected EntityManager em;
@Override
public boolean insertPerson(String name, boolean sex, Short age,
Date birthday) {
try{
Person person=new Person();
person.setName(name);
person.setSex(sex);
person.setAge(age);
person.setBirthday(birthday);
em.persist(person);
}catch(Exception e){
e.printStackTrace();
return false;
}
// TODO Auto-generated method stub
return true;
}
@Override
public String getPersonNameById(int personid) {
// TODO Auto-generated method stub
Person person=em.find(Person.class, Integer.valueOf(personid));
return person.getName();
}
public Person getPersonByID(int personid) {
return em.find(Person.class, personid);
}
public boolean updatePerson(Person person) {
try {
em.merge(person);//更新数据用merge
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
public List getPersonList() {
Query query = em.createQuery("from Person order by personid asc");
List list = query.getResultList();
return list;
}
}
上面我们使用到了一个对象:EntityManager em,EntityManager 是由EJB容器自动地管理和配置的,不需要用户自己创建,他用作操作实体Bean。关于他的更多介绍请参考持久化实体管理器EntityManager。 上面em.find()方法用作查询主键ID 为personid的记录。em.persist()方法用作向数据库插入一条记录。
大家可能感觉奇怪,在类中并没有看到对EntityManager em进行赋值,后面却可以直接使用他。这是因为在实体Bean加载时,容器通过@PersistenceContext注释动态注入EntityManager 对象。
如果persistence.xml文件中配置了多个不同的持久化内容。你需要指定持久化名称注入EntityManager 对象,可以通过@PersistenceContext注释的unitName属性进行指定,例:
@PersistenceContext(unitName="ejb")
EntityManager em;
如果只有一个持久化内容配置,不需要明确指定。
下面是persistence.xml文件的配置:
<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
<persistence-unit name="ejb">
<jta-data-source>java:/MySqlDS</jta-data-source>
<properties>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
三.打包项目并发布
1. 配置数据源文件mysql-ds.xml并放置在[jboss_home]/server/deploy/deploy 目录,把数据库驱动Jar 包mysql-connector-java-bin.jar放置在[Jboss_home]\server\default\lib 目录下,放置后需要重启Jboss服务器。如果数据源已经存在就不需要配置。
2. 配置persistence.xml文件,在文件中指定使用的源据源及各项参数。
3. 把实体类和persistence.xml文件打成Jar,persistence.xml 放在jar 文件的META-INF目录
打包方法:在eclipse中右键项目EJBStudy->export->java->jar file,然后选择要打包的内容,如下图所示:
将生成的EJBStudy.jar放到目录jboss-5.0.1.GA\server\default\deploy下。这个时候eclipse的console中会提示信息:
13:51:33,390 INFO [Ejb3DependenciesDeployer] Encountered deployment AbstractVFSDeploymentContext@1458635375{vfszip:/D:/Program%20Files%20(x86)/JavaEE/jboss-5.0.1.GA/server/default/deploy/EJBStudy.jar/}
13:51:33,391 INFO [Ejb3DependenciesDeployer] Encountered deployment AbstractVFSDeploymentContext@1458635375{vfszip:/D:/Program%20Files%20(x86)/JavaEE/jboss-5.0.1.GA/server/default/deploy/EJBStudy.jar/}
13:51:33,417 INFO [JBossASKernel] Created KernelDeployment for: EJBStudy.jar
13:51:33,417 INFO [JBossASKernel] installing bean: jboss.j2ee:jar=EJBStudy.jar,name=PersonDAOBean,service=EJB3
13:51:33,417 INFO [JBossASKernel] with dependencies:
13:51:33,417 INFO [JBossASKernel] and demands:
13:51:33,417 INFO [JBossASKernel] jboss.ejb:service=EJBTimerService
13:51:33,417 INFO [JBossASKernel] persistence.unit:unitName=#ejb
13:51:33,417 INFO [JBossASKernel] and supplies:
13:51:33,418 INFO [JBossASKernel] jndi:PersonDAOBean/remote-edu.sjtu.erp.ejbstudy.dao.PersonDAO
13:51:33,418 INFO [JBossASKernel] Class:edu.sjtu.erp.ejbstudy.dao.PersonDAO
13:51:33,418 INFO [JBossASKernel] jndi:PersonDAOBean/remote
13:51:33,418 INFO [JBossASKernel] Added bean(jboss.j2ee:jar=EJBStudy.jar,name=PersonDAOBean,service=EJB3) to KernelDeployment of: EJBStudy.jar
13:51:33,426 INFO [PersistenceUnitDeployment] Starting persistence unit persistence.unit:unitName=#ejb
13:51:33,428 WARN [Ejb3Configuration] Persistence provider caller does not implement the EJB3 spec correctly. PersistenceUnitInfo.getNewTempClassLoader() is null.
13:51:33,429 INFO [AnnotationBinder] Binding entity from annotated class: edu.sjtu.erp.ejbstudy.bean.Person
13:51:33,429 INFO [EntityBinder] Bind entity edu.sjtu.erp.ejbstudy.bean.Person on table Person
13:51:33,437 INFO [HibernateSearchEventListenerRegister] Unable to find org.hibernate.search.event.FullTextIndexEventListener on the classpath. Hibernate Search is not enabled.
13:51:33,438 INFO [ConnectionProviderFactory] Initializing connection provider: org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider
13:51:33,438 INFO [InjectedDataSourceConnectionProvider] Using provided datasource
13:51:33,438 INFO [SettingsFactory] RDBMS: MySQL, version: 5.5.16
13:51:33,438 INFO [SettingsFactory] JDBC driver: MySQL-AB JDBC Driver, version: mysql-connector-java-5.1.18 ( Revision: tonci.grgin@oracle.com-20110930151701-jfj14ddfq48ifkfq )
13:51:33,439 INFO [Dialect] Using dialect: org.hibernate.dialect.MySQLDialect
13:51:33,439 INFO [TransactionFactoryFactory] Transaction strategy: org.hibernate.ejb.transaction.JoinableCMTTransactionFactory
13:51:33,439 INFO [TransactionManagerLookupFactory] instantiating TransactionManagerLookup: org.hibernate.transaction.JBossTransactionManagerLookup
13:51:33,439 INFO [TransactionManagerLookupFactory] instantiated TransactionManagerLookup
13:51:33,439 INFO [SettingsFactory] Automatic flush during beforeCompletion(): disabled
13:51:33,439 INFO [SettingsFactory] Automatic session close at end of transaction: disabled
13:51:33,439 INFO [SettingsFactory] JDBC batch size: 15
13:51:33,439 INFO [SettingsFactory] JDBC batch updates for versioned data: disabled
13:51:33,439 INFO [SettingsFactory] Scrollable result sets: enabled
13:51:33,439 INFO [SettingsFactory] JDBC3 getGeneratedKeys(): enabled
13:51:33,439 INFO [SettingsFactory] Connection release mode: auto
13:51:33,439 INFO [SettingsFactory] Maximum outer join fetch depth: 2
13:51:33,439 INFO [SettingsFactory] Default batch fetch size: 1
13:51:33,439 INFO [SettingsFactory] Generate SQL with comments: disabled
13:51:33,439 INFO [SettingsFactory] Order SQL updates by primary key: disabled
13:51:33,440 INFO [SettingsFactory] Order SQL inserts for batching: disabled
13:51:33,440 INFO [SettingsFactory] Query translator: org.hibernate.hql.ast.ASTQueryTranslatorFactory
13:51:33,440 INFO [ASTQueryTranslatorFactory] Using ASTQueryTranslatorFactory
13:51:33,440 INFO [SettingsFactory] Query language substitutions: {}
13:51:33,440 INFO [SettingsFactory] JPA-QL strict compliance: enabled
13:51:33,440 INFO [SettingsFactory] Second-level cache: enabled
13:51:33,440 INFO [SettingsFactory] Query cache: disabled
13:51:33,440 INFO [SettingsFactory] Cache region factory : org.hibernate.cache.impl.bridge.RegionFactoryCacheProviderBridge
13:51:33,440 INFO [RegionFactoryCacheProviderBridge] Cache provider: org.hibernate.cache.HashtableCacheProvider
13:51:33,440 INFO [SettingsFactory] Optimize cache for minimal puts: disabled
13:51:33,440 INFO [SettingsFactory] Cache region prefix: persistence.unit:unitName=#ejb
13:51:33,440 INFO [SettingsFactory] Structured second-level cache entries: disabled
13:51:33,440 INFO [SettingsFactory] Echoing all SQL to stdout
13:51:33,440 INFO [SettingsFactory] Statistics: disabled
13:51:33,440 INFO [SettingsFactory] Deleted entity synthetic identifier rollback: disabled
13:51:33,440 INFO [SettingsFactory] Default entity-mode: pojo
13:51:33,440 INFO [SettingsFactory] Named query checking : enabled
13:51:33,443 INFO [SessionFactoryImpl] building session factory
13:51:33,447 INFO [SessionFactoryObjectFactory] Factory name: persistence.unit:unitName=#ejb
13:51:33,447 INFO [NamingHelper] JNDI InitialContext properties:{java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory, java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces}
13:51:33,457 INFO [SessionFactoryObjectFactory] Bound factory to JNDI name: persistence.unit:unitName=#ejb
13:51:33,457 WARN [SessionFactoryObjectFactory] InitialContext did not implement EventContext
13:51:33,459 INFO [SchemaExport] Running hbm2ddl schema export
13:51:33,459 INFO [SchemaExport] exporting generated schema to database
13:51:33,532 INFO [SchemaExport] schema export complete
13:51:33,534 INFO [NamingHelper] JNDI InitialContext properties:{java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory, java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces}
13:51:33,550 INFO [SessionSpecContainer] Starting jboss.j2ee:jar=EJBStudy.jar,name=PersonDAOBean,service=EJB3
13:51:33,551 INFO [EJBContainer] STARTED EJB: edu.sjtu.erp.ejbstudy.impl.PersonDAOBean ejbName: PersonDAOBean
13:51:33,558 INFO [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
PersonDAOBean/remote - EJB3.x Default Remote Business Interface
PersonDAOBean/remote-edu.sjtu.erp.ejbstudy.dao.PersonDAO - EJB3.x Remote Business Interface
我们在mysql数据库中也会看到ejb数据中创建了一张person表。
四.测试
创建一个EJB客户端来测试,代码如下
package edu.sjtu.erplab.ejb.test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import edu.sjtu.erp.ejbstudy.dao.PersonDAO;
public class EJBClient {
/**
* @param args
* @throws ParseException
*/
public static void main(String[] args) throws ParseException {
// TODO Auto-generated method stub
Properties props=new Properties();
//坑爹的写成:org.jnp.interface.NamingContextFactory
props.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
props.setProperty("java.naming.provider.url", "localhost:1099");
props.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming");
try
{
InitialContext ctx=new InitialContext(props);
//InitialContext ctx=new InitialContext();
PersonDAO persondao = (PersonDAO) ctx.lookup("PersonDAOBean/remote");
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
persondao.insertPerson("xuwei", true, (short)22,formatter.parse("1985-10-17"));//添加一个人
System.out.println(persondao.getPersonNameById(1)); //取personid为1的人
}catch(NamingException e){
System.out.println(e.getMessage());
}
}
}
不明白为什么会有如下这么多警告,不过数据已经正确插入表person中
13:54:55,200 WARN [InterceptorsFactory] EJBTHREE-1246: Do not use InterceptorsFactory with a ManagedObjectAdvisor, InterceptorRegistry should be used via the bean container
13:54:55,200 WARN [InterceptorsFactory] EJBTHREE-1246: Do not use InterceptorsFactory with a ManagedObjectAdvisor, InterceptorRegistry should be used via the bean container
13:54:55,200 WARN [InterceptorRegistry] applicable interceptors is non-existent for public edu.sjtu.erp.ejbstudy.bean.Person edu.sjtu.erp.ejbstudy.impl.PersonDAOBean.getPersonByID(int)
13:54:55,203 WARN [InterceptorRegistry] applicable interceptors is non-existent for public boolean edu.sjtu.erp.ejbstudy.impl.PersonDAOBean.insertPerson(java.lang.String,boolean,java.lang.Short,java.util.Date)
13:54:55,205 WARN [InterceptorRegistry] applicable interceptors is non-existent for public boolean edu.sjtu.erp.ejbstudy.impl.PersonDAOBean.updatePerson(edu.sjtu.erp.ejbstudy.bean.Person)
13:54:55,208 WARN [InterceptorRegistry] applicable interceptors is non-existent for public java.lang.String edu.sjtu.erp.ejbstudy.impl.PersonDAOBean.getPersonNameById(int)
13:54:55,210 WARN [InterceptorRegistry] applicable interceptors is non-existent for public java.util.List edu.sjtu.erp.ejbstudy.impl.PersonDAOBean.getPersonList()
13:54:55,213 WARN [InterceptorRegistry] applicable interceptors is non-existent for public edu.sjtu.erp.ejbstudy.bean.Person edu.sjtu.erp.ejbstudy.impl.PersonDAOBean.getPersonByID(int)
13:54:55,216 WARN [InterceptorRegistry] applicable interceptors is non-existent for public boolean edu.sjtu.erp.ejbstudy.impl.PersonDAOBean.insertPerson(java.lang.String,boolean,java.lang.Short,java.util.Date)
13:54:55,218 WARN [InterceptorRegistry] applicable interceptors is non-existent for public boolean edu.sjtu.erp.ejbstudy.impl.PersonDAOBean.updatePerson(edu.sjtu.erp.ejbstudy.bean.Person)
13:54:55,221 WARN [InterceptorRegistry] applicable interceptors is non-existent for public java.lang.String edu.sjtu.erp.ejbstudy.impl.PersonDAOBean.getPersonNameById(int)
13:54:55,223 WARN [InterceptorRegistry] applicable interceptors is non-existent for public java.util.List edu.sjtu.erp.ejbstudy.impl.PersonDAOBean.getPersonList()
13:54:55,227 INFO [STDOUT] Hibernate: insert into Person (age, birthday, name, sex) values (?, ?, ?, ?)
13:54:55,301 INFO [STDOUT] Hibernate: select person0_.personid as personid72_0_, person0_.age as age72_0_, person0_.birthday as birthday72_0_, person0_.name as name72_0_, person0_.sex as sex72_0_ from Person person0_ where person0_.personid=?