Elton's Blog

Tag: ejb3

EJB3入门(4)实体Bean

by on 六.17, 2009, under Java

实体Bean就是跟数据库中某个表对应的一个类。 类的每个实例对应数据库的一行记录。如果用过hibernate的人一定很熟悉这个概念。这个就是所谓的ORM模型。Jboss就是使用的Hibernate来实现的。

假设数据库中有这样一个表

mysql 表结构

mysql 表结构


我们来写一个EJB应用,来把用户的密码得到。

先对Jboss做相关配置,便于读取数据库。
设置数据源
拷贝jboss安装目录下docs/jca中的mysql-ds.xml到default/deploy目录中,对其中的参数进行修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
  <local-tx-datasource>
    <jndi-name>ejb</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>
    <metadata>
       <type-mapping>mySQL</type-mapping>
    </metadata>
  </local-tx-datasource>
</datasources>

再将mysql的驱动拷贝到default/lib中
在源代码目录下的META-INF中建立配置文件persistence.xml,以便ejb项目可以使用jboss的数据源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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="myentity">
        <jta-data-source>java:/ejb</jta-data-source>
        <properties>
            <property name="hibernate.hbm2ddl.auto" value="none" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
        </properties>
    </persistence-unit>
</persistence>

其中jta-data-source中java后面的值一定要跟jboss数据源的jndi-name一致

下面就可以开始写一个与上面的表对应的实体Bean了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package me.prosight.entity;
 
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
 
@Entity
@Table(name="users")
public class User {
	private int id;
	private String name;
	private String password;
 
	@Id
	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;
	}
 
	@Column(name = "password_md5")
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
}

@Entity 标记表明这是一个实体bean
@Table 标记声明数据库的表的名字,如果不声明,同类名
@Id 表明这个字段是主键
@Column 标记说明这个属性对应的数据库中的字段名,不声明则同属性名。

我们需要建立一个无状态的session bean来调用实体bean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package me.prosight.service;
 
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
 
import me.prosight.entity.User;
 
/**
 * Session Bean implementation class UserBean
 */
@Stateless
public class UserBean implements UserBeanRemote {
 
	@PersistenceContext(unitName="myentity")
	protected EntityManager em;
 
	public String getPassword() {
		User user = em.find(User.class, 1);
		return user.getPassword();
	}
 
}

其中PersistenceContext中的unitName一定要跟persistence.xml中的persistence-unit中的name一致

最后,再写个测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package me.prosight.client;
 
import javax.naming.InitialContext;
import javax.naming.NamingException;
 
import me.prosight.service.UserBeanRemote;
 
public class Client {
	public static void main(String[] args) throws NamingException {
		InitialContext ctx = new InitialContext();
		UserBeanRemote user = (UserBeanRemote)ctx.lookup("UserBean/remote");
 
		System.out.println(user.getPassword());
	}
 
}

部署好ejb后,再使用这个类测试,应该就可以得到数据库中的数据了。

Leave a Comment :, more...

EJB3入门(3)本地接口

by on 六.16, 2009, under Java

之前用到的都是远程接口,顾名思义,远程接口就是提供不再同一个虚拟机中的两端程序来访问的。适合于分布式部署。但是有的时候客户端和服务端又在一个jvm中,比如在一个tomcat或者jboss的web容器中。这个时候就没有必要用远程接口了,毕竟浪费资源。可以改用local接口。

如果你尝试将上一节中的remote直接替换成local,再执行客户端,你会发现如下错误:

1
Could not find InvokerLocator URL at JNDI address "ShoppingCartBean/local"; looking up local Proxy from Remote JVM?

这说明你试图通过远程的jvm来调用本地的端口,因为客户端执行的这个jvm与ejb容器的jvm是两个不同的虚拟机。所以本地接口调用会失败。

在这里我们再建立一个web工程,创建web工程的时候,可以顺便创建一个EAR工程。

创建web工程

创建web工程

然后在这个web工程中加入对之前shoppingcart项目的引用。注意,这里已经将shoppingcart项目中的接口改为local方式。

修改Build Path

修改Build Path

在Java build path中,点击projects标签,点击add按钮,加入shoppingcart的项目

加入相关项目

加入相关项目

之后,在web项目中新建一个jsp页面,如index.jsp,代码如下:

1
 

之后就可以将EAR项目导出到jboss的部署目录中了。

导出EAR

导出EAR

部署好以后,jboss的输出会提示:

1
19:26:53,132 INFO  [TomcatDeployment] deploy, ctxPath=/EJBWeb

之后就可以在浏览器中输入localhost:8080/EJBWeb来测试本地接口了。

Leave a Comment :, more...

EJB3入门(2)Stateful Session bean

by on 六.16, 2009, under Java

有了上节无状态session bean的基础,这回试着做一个有状态的session bean。 有状态的session bean语法上跟无状态session bean只有一个元标记的区别,把实现类里面的@Stateless替换成@Stateful就可以了。

如果使用Stateful Sessionbean,客户端在使用同一个SessionBean对象实例时可以保存状态,也就是说,在多次引用该对象时实际上在服务端是使用的同一个Sessionbean的对象实例,而无状态sessionbean使用了不同的sessionbean对象实例,因此,是无法保存状态的。

最直接的例子就是购物车,购物车是跟着用户来的,需要保持状态,否则人家挑好的东西都不见了。

先写一个接口:

1
2
3
4
5
6
7
8
9
10
11
package me.prosight;
 
import java.util.List;
import javax.ejb.Remote;
 
@Remote
public interface ShoppingCartRemote {
 
	public void addProduct(String name);
	public List<string> getAllProducts();
}

再写一个实现类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package me.prosight;
 
import java.util.ArrayList;
import java.util.List;
 
import javax.ejb.Stateful;
 
@Stateful
public class ShoppingCartBean implements ShoppingCartRemote {
 
	private List<string> shoppingCart = new ArrayList<string>();
 
	@Override
	public void addProduct(String name) {
		shoppingCart.add(name);
 
	}
 
	@Override
	public List<string> getAllProducts() {
		return shoppingCart;
	}
 
}

最后再写一个测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package me.prosight;
 
import java.util.List;
 
import javax.naming.InitialContext;
import javax.naming.NamingException;
 
public class Client {
 
	public static void main(String[] args) throws NamingException {
		InitialContext ctx = new InitialContext();
		ShoppingCartRemote cart = (ShoppingCartRemote) ctx.lookup("ShoppingCartBean/remote");
		cart.addProduct("Apple");
		cart.addProduct("IBM");
		cart.addProduct("Dell");
 
		List<string> products = cart.getAllProducts();
		for (String product : products)
		{
			System.out.println(product);
		}
 
	}
 
}

在客户端调用时,需要将ShoppingCart接口复制到客户端,当然,@Remote可以去掉。别忘了引用JBoss安装目录中的client目录中的jar文件。客户端仍然使用了jndi.properties文件来配置相应的信息,该文件位于源代码目录下,内容如下;

1
2
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=localhost

在执行上面的程序后,将输出如下的信息:

1
2
3
Apple
IBM
Dell

要注意的是,需要使用同一个sessionbean对象实例(cart)才能保存状态。如果在web应用程序中,需要将cart对象保存在Session中,这样在同一个会话中的用户就可以使用该购物车对象了。

3 Comments :, more...

EJB3入门(1)Stateless Session bean

by on 六.13, 2009, under Java

一直想学EJB,今天有空开始学习。

下载相关资源
JDK 1.6u14 http://java.sun.com
eclipse 3.4 http://www.eclipse.org
Jboss tools http://jboss.org/tools
Jboss AS 5.1.0AS http://www.jboss.org/jbossas

安装配置好后,我们开始写第一个EJB, 先写个无状态的Session Bean — Hello world

先定义接口

1
2
3
4
5
6
7
8
package me.prosight;
import javax.ejb.Remote;
 
@Remote
public interface HelloRemote {
	public String sayHello(String name);
 
}

再定义实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package me.prosight;
 
import javax.ejb.Stateless;
 
/**
 * Session Bean implementation class Hello
 */
@Stateless
public class HelloBean implements HelloRemote {
 
	@Override
	public String sayHello(String name) {
		return "Hello " + name;
	}
 
}

启动Jboss服务器,将刚刚的EJB应用部署到jboss中。右键点击项目名称,然后选择Export–>EJB/JAR file

EJB项目部署

EJB项目部署

将这个Jar包部署到/server/default/deploy中,一会jboss就会自动将这个应用部署到jboss的容器中,后面我们就可以使用这个ejb了。

再写一个测试客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package me.prosight;
 
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
 
public class HelloClent {
 
	public static void main(String[] args) throws NamingException {
		Context ctx = new InitialContext();
		HelloRemote hello = (HelloRemote) ctx.lookup("HelloBean/remote");
		String msg = hello.sayHello("Elton");
		System.out.println(msg);
	}
 
}

客户端要注意两件事情

  1. 确保正确设置了JNDI
  2. 在引用远程的EJB bean的时候,要使用对应的接口来引用而不是实现类。

JNDI是Java命名和目录接口,是用来标记EJB的bean位置的。 如果你的客户端和EJB不在一个JVM中运行,就需要配置JNDI。当你部署好一个EJB的应用,会在控制台中显示出调用这个EJB的所有的JNDI名称,如:

JNDI

JNDI

在InitialContext的lookup方法中就可以使用这个名称来引用相关的Bean了。

配置JNDI有两个方法,一个就是在源文件目录中建立jndi.properties文件,我的这个文件内容如下:

1
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces java.naming.provider.url=localhost:1099

provide.url指定的是EJB容器的地址和端口,可以使用IP地址来指定你的EJB容器装在哪台服务器上。

或者在程序中以编程的方式来指定,在new InitialContext()前,输入如下代码:

1
2
3
4
5
Properties props = new Properties();
props.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
props.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming");
props.setProperty("java.naming.provider.url", "localhost:1099");
InitialContext ctx = new InitialContext(props);

运行这个程序,将会在控制台中看到:

程序输出

程序输出

第一个EJB的Hello World就完成了。还很简单吧。

工程源代码

Leave a Comment :, more...

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!

Visit my friends!

A few highly recommended friends...