EJB学习

时间:2024-03-14 19:07:09

工作场景:公司的一套开发工具需要使用EJB部署,老大想让我先学学EJB,熟悉EJB项目创建。

在搭建EJB项目之前,我们先来认识一下EJB,EJB是sun的JavaEE服务器组件模型,设计目标与核心应用是部署分布式应用程序。简单来说就是把已经编写好的程序(即:类)打包放在服务器上执行。关于EJB和WEB打包问题,可以参考学习:https://blog.csdn.net/zjx86320/article/details/47111693

1.环境配置

 

        ·Helios Service Release 2

        ·jboss-5.1.0.GA

        ·1.6.0_10-rc2

        ·5.5.59-log MySQL Community Server (GPL)

 

2.创建一个EJB项目

 

依次点击File → New → EJB Project,填写项目名称如下:

        EJB学习

        然后点击Next → Finish;

        选中EJB项目下的ejbModule文件夹,右击→ New→ Session Bean(EJB 3.X),创建一个Session Bean.

       EJB学习

       EjbTestRemote 接口:

       

package com.test.ejb;
import javax.ejb.Remote;

@Remote
public interface EjbTestRemote {
    
    String sayHello(String username);
}
 


       EjbTest 实现类:

       

package com.test.ejb.impl;


import javax.ejb.Stateless;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import com.test.ejb.EjbTestRemote;
import com.test.ejb.Other;

/**
 * Session Bean implementation class EjbTest
 */
@Stateless
public class EjbTest implements EjbTestRemote {
    
    /**
     * Default constructor. 
     */
    public EjbTest() {
    }

    @Override
    public String sayHello(String username) {
        
       return "Hello," + username + " welcome to EJB.";
    }

}
 

    3.部署

        部署有两种方式:

        ①在eclipse中发布

        在之前创建好的Server中,右击Add and Remove,添加这个项目,然后Start即可。

        ②打包后再部署到指定的Server下

        在工程上右键→ Export→ EJB JAR file,选择JBOSS服务器部署目录:                                     JBOSS_HOME/server/default/deploy,完成即可。

    4.创建客户端

        ①点击 File → New → Other … → Java Project

        EJB学习

        ②添加对上面ejb_01.jar的引用和JBOSS Client的jar包($JBOSS_HOME/clent/jbossall-clent.jar),添加到ClassPath路径下。

        EJB学习

       ③编写客户端测试类,代码如下

       

package com.ejb.test;

import java.util.Properties;

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

import com.test.ejb.EjbTestRemote;

public class EjbClientTest {
    
    public static void main(String[] args){
        try{
            Properties props = new Properties();
            
            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");
            System.out.println(">>>> InitialContext ");
            
            InitialContext ctx = new InitialContext(props);
            
            System.out.println(">>>> lookup  ");
            String serviceName = "EjbTest/remote";
            //将从EJB容器中获取的代理对象转为接口
            EjbTestRemote etr = (EjbTestRemote) ctx.lookup(serviceName);
            System.out.println(">>>> 调用sayHello(\"三玖\")");
            String result = etr.sayHello("ejb.com");
            System.out.println(">>>> 结果 = " + result);
        }catch (NamingException e) {
            e.printStackTrace();
        }
    }

}
 

    5.运行客户端

        先启动JBOSS;

        运行客户端代码,证明我们远程调用成功。

        EJB学习

在部署期间可能出现的错误:

    Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy2 cannot be cast to com.test.ejb.EjbTest at com.ejb.test.EjbClientTest.main(EjbClientTest.java:12)

出现的原因有二:

    1.你的EjbTest没有显示sayHello接口

   

@Stateless
@Remote({EjbTestRemote.class})
public class EjbTest implements EjbTestRemote{
 
}

    2.将从EJB容器中获取的代理对象转为接口

EjbTestRemote etr= (EjbTestRemote) initialContext
                .lookup("EjbTest/remote");

 

4.Enterprise Bean(企业Bean)和Entity Bean(实体Bean)的学习

可以参照学习:https://blog.csdn.net/zjx86320/article/details/47146295

5.EJB Entity Bean(实体Bean)搭建

5.1、MySql数据库的配置
5.1.1. 配置数据源
在 %JBOSS_HOME%/docs/examples/jca 目录下找到一个名叫 "mysql-db.xml" 的文件,这个是官方为我们写好的针对mysql的数据源配置文件,我们改改它就行了。

将 mysql-db.xml 复制到 /server/default/deploy 目录下,并将文件内容修改为:

<?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/ejb</connection-url>
    <driver-class>com.mysql.jdbc.Driver</driver-class>
    <user-name>root</user-name>
    <password></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>
<user-name>是你的mysql数据库用户名,同理<password>是连接密码。

5.1.2在项目根目录下新建一个META-INF文件夹→新建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">  
     
 <!-- entity就是EntityManager服务名 -->
 <persistence-unit name="entity" transaction-type="JTA">  
     <!-- 这里必须跟mysql-db.xml文件中的<jndi-name>一样,即MySqlDs -->
    <jta-data-source>java:/MySqlDS</jta-data-source>  
    <!-- 以下是hibernate的相关配置,可省略 -->
    <properties>  
             <!--配置Hibernate方言 -->
             <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
             <!--自动输出schema创建DDL语句 -->
             <property name="hibernate.hbm2ddl.auto" value="update"/>
             <!--显示最终执行的SQL-->
             <property name="hibernate.show_sql" value="true"/>
             <!--格式化显示的SQL-->
             <property name="hibernate.format_sql" value="true"/>
             <property name="hibernate.connection.characterEncoding" value="UTF-8" />
    </properties>
 </persistence-unit>  
    
</persistence> 

5.2开发实体bean:

package com.test.entity;
 
import java.io.Serializable;
 
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
 
@Entity
@Table(name = "DB_USER")
public class User implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    @Id
    @Column(name = "C_ID")
    private int id;
    @Column(name = "C_NAME")
    private String name;
    @Column(name = "C_PASSWORD")
    private String pwd;
    
    //get() and set()
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPwd() {
        return pwd;
    }
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
    
    
}

添加对实体bean进行增删改查,

新建会话bean:

新建接口UserBeanLocal

package com.test.ejb;

import javax.ejb.Local;

import com.test.entity.User;

@Local
public interface UserBeanLocal {
    void createUser(User user); //创建User
    User getUser(int id); //查询并获取User
    void delUser(int id); //删除User
    void updateUser(User user); //更新User
}
 

2.定义接口的实现类:

package com.test.ejb.impl;

import java.util.List;

import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import com.test.ejb.UserBeanLocal;
import com.test.ejb.UserBeanRemote;
import com.test.entity.User;

/**
 * 实例Bean
 * @author huchao
 */
@Stateless
@Remote(UserBeanRemote.class)
public class UserBean implements UserBeanRemote {

    @PersistenceContext(unitName="entity")
    private EntityManager manager;
    
    public void createUser(User user) {
        //对新建状态的实体进行保存,在实体bean中有四种状态:
        //新建状态,托管状态,游离状态,删除状态
        manager.persist(user);
    }

    public User getUser(int id) {
        return manager.find(User.class, id);
    }
    
    @SuppressWarnings("unchecked")
    public List<User> getUsers() {
        return manager.createQuery("select o from User o").getResultList();
    }

    public void delUser(int id) {
        //删除数据没必要再查询,使用getReference性能比较好,
        //getReference得到的是托管状态的实体。
        //manager.remove(manager.merge(user));
        manager.remove(manager.getReference(User.class, id));
    }

    public void updateUser(User user) {
        //调用merge的前提是person已经处于游离状态,在这个状态的情况下,
        //对bean进行修改,才调用merge方法。
        //如果对象属于托管状态,我们直接调用person的save方法就可以进行修改了。
        manager.merge(user);
    }

}

会话bean和实体bean都编制好了,接下来对应用进行打包发布。我们这里还是采用上述两种方法之一(也可以使用Ant,后面打算学习下)。

因为这个持久化单元配置文件使用到了数据源,所以在发布之前要确保发布了数据源。

接下来可以编写客户端方法了,进行测试:

package com.ejb.test;

import java.util.List;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;

import com.test.ejb.UserBeanRemote;
import com.test.entity.User;


/**
 * 通过工厂的方式通过jndi去查找相应的ejb
 * @author huchao
 *
 */
public class UserClient {
    //@EJB(beanName="UserBean")  UserBeanRemote ubr1;
    
    public static void main(String[] args) {
    try {
        System.out.println(">>>> InitialContext ");
        Context context = initContext();
        System.out.println(">>>> lookup  ");
       //将从EJB容器中获取的代理对象转为接口
        UserBeanRemote ubr = (UserBeanRemote)context.lookup("UserBean/remote");
        
        //add(ubr);
        //query(ubr);
        queryAll(ubr);
        //del(ubr);
        //update(ubr);
        
        System.out.println("success!");
    }
    catch (Exception ex) {
        ex.printStackTrace();
    }
    }
    
    /**
     * 增
     * @param ubr
     */
    public static void add(UserBeanRemote ubr){
        System.out.println(">>>> 调用createUser(\"user\")");
        User user = new User();
        user.setId(4);
        user.setName("bruce lee");
        user.setPwd("1234567");
        
        ubr.createUser(user);
        
    }
    
    /**
     * 删
     * @param ubr
     */
    public static void del(UserBeanRemote ubr){
        System.out.println(">>>> 调用delUser(\"user\")");
        int id = 4;
        ubr.delUser(id);
    }
    /**
     * 改
     * @param ubr
     */
    public static void update(UserBeanRemote ubr){
        System.out.println(">>>> 调用updateUser(\"user\")");
        int id = 4;
        User user = ubr.getUser(id);
        user.setName("bruce leee");
        //user.setPwd("123456789");
        
        ubr.updateUser(user);
    }
    /**
     * 查
     * @param ubr
     */
    public static void query(UserBeanRemote ubr){
        System.out.println(">>>> 调用getUser(\"id\")");
        int id = 4;
        User user = ubr.getUser(id);
        
        System.out.println("id为" + id + "的用户为:" + user.getName());
    }
    
    /**
     * 查
     * @param ubr
     */
    public static void queryAll(UserBeanRemote ubr){
        System.out.println(">>>> 调用getUser(\"id\")");
        int id = 4;
        List<User> userList = ubr.getUsers();
        
        System.out.println("用户为:" + userList);
    }
    
    /**
     * 这一部分是写死的
     * 固定写法
     */
    public static Context initContext() throws javax.naming.NamingException {
    Properties prop = new Properties();
    prop.put(Context.INITIAL_CONTEXT_FACTORY,"org.jnp.interfaces.NamingContextFactory");
    prop.put(Context.URL_PKG_PREFIXES,"org.jboss.naming:org.jnp.interfaces");
    prop.put(Context.PROVIDER_URL, "jnp://localhost:1099");
    
    return new InitialContext(prop);
    }
 
}

EJB学习

产生乱码,将数据库修改为UTF-8,

或者修改

<?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/ejb?seUnicode=true&amp;characterEncoding=utf-8</connection-url>
    <driver-class>com.mysql.jdbc.Driver</driver-class>
    <user-name>root</user-name>
    <password></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就开发就完了。

 

参照学习:https://blog.csdn.net/Jerome_s/article/details/37358569

https://blog.csdn.net/neosmith/article/details/9327549

https://blog.csdn.net/zjx86320/article/details/47145769