工作场景:公司的一套开发工具需要使用EJB部署,老大想让我先学学EJB,熟悉EJB项目创建。
在搭建EJB项目之前,我们先来认识一下EJB,EJB是sun的JavaEE服务器端组件模型,设计目标与核心应用是部署分布式应用程序。简单来说就是把已经编写好的程序(即:类)打包放在服务器上执行。关于EJB和WEB打包问题,可以参考学习:https://blog.csdn.net/zjx86320/article/details/47111693
1.环境配置
·Helios Service Release 2
·1.6.0_10-rc2
·5.5.59-log MySQL Community Server (GPL)
2.创建一个EJB项目
依次点击File → New → EJB Project,填写项目名称如下:
然后点击Next → Finish;
选中EJB项目下的ejbModule文件夹,右击→ New→ Session Bean(EJB 3.X),创建一个Session Bean.
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_01.jar的引用和JBOSS Client的jar包($JBOSS_HOME/clent/jbossall-clent.jar),添加到ClassPath路径下。
③编写客户端测试类,代码如下
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;
运行客户端代码,证明我们远程调用成功。
在部署期间可能出现的错误:
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);
}
}
产生乱码,将数据库修改为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&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