`

EJB 3 初次学习小结

阅读更多
从昨天到今天晚上,从对EJB的不熟悉,到可以搭建出基于EJB一站式的HELLOWORLD(发出JNDI查找---业务BEAN----JPA查询----返回结果),花了大概接近15个小时的时间,收获非常大,第一就是部署,部署明显还是没有JAVA WEB来的快,来的爽。但是在学习过程中也体验到了一些快乐,EJB还是简单的,不过相对于SPRING这类DI框架来说,还是要复杂一些。

学习过程中,我首先把手头上的《EJB实战》,《企业级EJB》这2本书大概的翻阅了一下,之后就开始找DEMO学习,学习过程中,感到了网络上学习资料之少,包括出了异常的不知所云,再到自己一个一个解决,到最后EJB程序跑成,走出了一段非常艰难的历程,首先就是环境,我使用了EJB3+JBOSS5。由于对EJB整体概念的迷糊,一开始一个BEAN写好了,都不知道应该往哪里放,怎么样去打包,相比JAVA WEB的应用,责要烦人很多。另外,出了很多莫名其妙的异常,我还发现一个问题,异常一般提示很少,GOOGLE到的东西几乎都是英文网页,从这点也可以看出国内对EJB3的应用还是不多,不像SSH,一GOOGLE能出一大堆信息。终于,自己最后解决了部署问题。EJB组件单独打成JAR,之后把显示层打成WEB格式的WAR。因为在EJB中可以使用注解,所以感觉还是很爽的,可以比较容易的去写各种BEAN,包括可以使用注解把接口打包成JNDI服务。之后在展现层使用JNDI去掉业务层服务。一开始最郁闷的异常就是因为对EJB部署概念的不熟悉,导致了走了许多冤枉路,一直出这个异常(javax.naming.NameNotFoundException: UserBean not bound)代码没有问题,可是JBOSS一直不把这个JNDI注册为服务,问题就是出在部署上,我在EJB项目的META-INF文件夹里添加了不应该添加的东西,导致JBOSS始终不去加载这个服务。最后还不容易解决,又出了问题,一开始我把一个接口注解成本地服务,可是JNDI一直无法获取的这个接口,最后注解成了远程服务,终于搞定,我还奇怪来着。最后就是整个DEMO包的架构问题,以前一直使用SSH2的组合,一直把WEB层也写到项目里,一开始写EJB的DEMO,我也这么干了,呵呵,问题可想而知了。不过在走了许多弯路之后,还是改了。把EJB与展现层分开了,现在还没写SERVLET,只是写了个MAIN,做了个TEST,感受颇多啊,EJB是强大的,这点不用否认了。还有一点,现在EJB3的开发速度如果熟练,我认为还是挺快的,当然,我没有使用过SSH2的注解,一直都是以XML为中心,在EJB上都换成了注解,爽死。唯一需要XML的就是persistence.xml,找一下配置在JBOSS上的JNDI数据源。

上个DEMO的代码吧,也为打算学习EJB3的朋友开个头,少走点弯路。



首先是一个简单的泛型DAO,接口与服务类(没有事务处理,没有测试,LOAD是可以用的,哈哈):


package com.core.support.ejbDao;

import java.io.Serializable;
import java.util.List;

import javax.persistence.Query;

public interface IBaseDAO<T,PK extends Serializable> {
	
	
	/**
	 * 根据Id查找一个类型为T的对象。
	 * @param clazz
	 * @param id
	 * @return
	 */
	public T load(Serializable id);

	/**
	 * 把实体持久化到数据库,并且使实体受到管制。
	 * @param t
	 */
	public void persist(T t);

	/**
	 * 持久化一个对象,该对象类型为T。
	 * @param t
	 */
	public void save(T t);
	
	/**
	 * 根据对象id删除一个对象,该对象类型为T
	 * @param t
	 */
	public void delete(T t);
	
	/**
	 * 根据ID删除对象
	 * @param id
	 */
	public void deleteById(PK id);
	
	/**
	 * 更新一个对象,主要用于更新一个在persistenceContext之外的一个对象。
	 * 
	 * @param transientObject
	 *            需要更新的对象,该对象不需要在persistenceContext中。
	 */
	void update(T transientObject);
	
    
	public Query createQuery(String jpql);

	/**
	 * 根据JPQL查询总数
	 * @param jpql
	 * @return
	 */
	public int getTotalCount(String jpql);

	/**
	 * 使用JPQL进行查询
	 * @param jpql
	 * @return
	 */
	public List<T> find(String jpql);

	/**
	 * 单条件的JPQL查询
	 * @param jpql
	 * @param param
	 * @return
	 */
	public List<T> find(String jpql, Object param);

	/**
	 * 多条件的JPQL查询
	 * @param jpql
	 * @param param
	 * @return
	 */
	public List<T> find(String jpql, Object... param);
	
	/**
	 * 更新或添加
	 * @param t
	 */
	public void saveOrUpdate(T t);
	
	/**
	 * 实体分离
	 */
	public void flush();
}


package com.core.support.ejbDao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;


public class BaseDAOImpl<T,PK extends Serializable> implements IBaseDAO<T,PK> {
	
	private Class<T> clazz;
	
	// 构造方法,根据实例类自动获取实体类类型
	public BaseDAOImpl() {
        this.clazz = null;
        Class c = getClass();
        Type t = c.getGenericSuperclass();
        if (t instanceof ParameterizedType) {
            Type[] p = ((ParameterizedType) t).getActualTypeArguments();
            this.clazz = (Class<T>) p[0];           
        }
    }
	
	@PersistenceContext(unitName="OpenStarBBS")
	 protected EntityManager em;
	 
	
	 public Query createQuery(String jpql) {
	  return em.createQuery(jpql);
	 }
	 
	 public void delete(T t) {
	  em.remove(t);
	 }
	 
	 public T load(Serializable id) {
	  return em.find(clazz,id);
	 }
	 
	 @SuppressWarnings("unchecked")
	 public List<T> find(String jpql, Object param) {
	  return em.createQuery(jpql).setParameter(1, param).getResultList();
	 }
	 
	 @SuppressWarnings("unchecked")
	 public List<T> find(String jpql, Object[] param) {
	  Query query = em.createQuery(jpql);
	  for (int i = 1; i <= param.length; i++) {
	   query.setParameter(i, param[i - 1]);
	  }
	  return query.getResultList();
	 }
	 
	 
	 @SuppressWarnings("unchecked")
	 public List<T> find(String jpql) {
	  return em.createQuery(jpql).getResultList();
	 }
	 
	 
	 @SuppressWarnings("unchecked")
	 public int getTotalCount(String jpql) {
	  return ((Long) em.createQuery(jpql).getSingleResult()).intValue();
	 }
	 
	 
	 public void persist(T t) {
	  em.persist(t);
	 }
	 
	 
	 public void save(T t) {
	  em.merge(t);
	 }
	 
	 
	 public void saveOrUpdate(T t) {
	  em.merge(t);
	 }


	 public void update(T transientObject) {
		em.merge(transientObject);
		
	}

	public void deleteById(PK id) {
		T object = this.load(id);
		this.delete(object);	
	}

	public void flush() {
		em.flush();
	}
	
}


以上这个可以复用。下面就是程序里的接口和类:

JAP ORM映射类(用工具通过数据库逆向工程):
package com.openstarbbs.model;

import javax.ejb.EJB;
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 com.core.support.ejbDao.IBaseDAO;

/**
 * User entity. @author MyEclipse Persistence Tools
 */
@Entity
@Table(name = "user", catalog = "openstarbbs")
public class User implements java.io.Serializable {

	// Fields

	private Integer id;
	private String name;
	private String age;

	@EJB
	private IBaseDAO baseDao;
	
	// Constructors

	/** default constructor */
	public User() {
	}

	/** full constructor */
	public User(String name, String age) {
		this.name = name;
		this.age = age;
	}

	public void saveUser(User user){
		baseDao.save(user);
	}
	
	// Property accessors
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "id", unique = true, nullable = false)
	public Integer getId() {
		return this.id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	@Column(name = "name", nullable = false, length = 45)
	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Column(name = "age", nullable = false, length = 45)
	public String getAge() {
		return this.age;
	}

	public void setAge(String age) {
		this.age = age;
	}

}


USER DAO,继承于泛型DAO。

package com.openstarbbs.user.dao;

import javax.ejb.Stateless;

import com.core.support.ejbDao.BaseDAOImpl;
import com.openstarbbs.model.User;

@Stateless
public class UserDao extends BaseDAOImpl<User,Long> implements IUserDao{

		
}


package com.openstarbbs.user.dao;

import javax.ejb.Local;

import com.core.support.ejbDao.IBaseDAO;
import com.openstarbbs.model.User;

@Local  
public interface IUserDao extends IBaseDAO<User,Long>{
	
}


业务层会话BEAN。

package com.openstarbbs.user.service;

import javax.ejb.Remote;

import com.openstarbbs.model.User;

@Remote
public interface IUserBean {
	
	public User getUser();
	
}


package com.openstarbbs.user.service;

import javax.ejb.EJB;
import javax.ejb.Remote;
import javax.ejb.Stateless;


import com.openstarbbs.model.User;
import com.openstarbbs.user.dao.IUserDao;


@Stateless
@Remote
public class UserBean implements IUserBean {
	
	@EJB
	private IUserDao userDao;
	
	public User getUser() {
		return userDao.load(1);
	}

}


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="OpenStarBBS" transaction-type="JTA">
  		<jta-data-source>java:/MySqlDS</jta-data-source>
  		<properties>
			<property name="hibernate.hbm2ddl.auto" value="update" />
			<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
		</properties>
  		
	</persistence-unit>
  
</persistence>



JBOSS数据源配置:

<?xml version="1.0" encoding="UTF-8"?>

<!-- See http://www.jboss.org/community/wiki/Multiple1PC for information about local-tx-datasource -->
<!-- $Id: mysql-ds.xml 88948 2009-05-15 14:09:08Z jesper.pedersen $ -->
<!--  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/openstarbbs</connection-url>
    <driver-class>com.mysql.jdbc.Driver</driver-class>
    <user-name>root</user-name>
    <password>1234</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>


之后把EJB项目打包成JAR,直接放到JBOSS的server\default\deploy目录下,观察JBOSS控制台,是否正常载入JAR,是否正常绑定我们自己定义的那些JNDI服务。

后面就是测试了,属于展现层的东西,我是单独做一个项目,之后把上面的JAR在导入新PATH中,包括把JBOSS中client目录的所有JAR也要导入PATH。

import javax.naming.InitialContext;
import javax.naming.NamingException;

import com.openstarbbs.user.service.IUserBean;
 
public class Test
{
    public static void main(String[] args)
    {
        try
        {
            InitialContext ctx = new InitialContext();
        
            IUserBean iuserBean = (IUserBean)ctx.lookup("UserBean/remote");
            System.out.println(iuserBean.getUser().getName());
            
        }
        catch(NamingException ne)
        {
            ne.printStackTrace();
        }
    }
}


OK,JAVA控制台输出:laoyang

成功。
  • 大小: 38 KB
分享到:
评论
2 楼 junzilan0929cn 2011-08-31  

学习了.
1 楼 xiaowur 2010-05-20  
写的很详细...
对我很有帮助

相关推荐

Global site tag (gtag.js) - Google Analytics