利用
JBOSS+MyEclipse
完成一个简单的
EJB
示例
目标:
1
、编写一个简单的无状态会话
Bean
,传入一个字符串参数,返回字符串
Hello +
字符串参数。
2
、通过
JSP
页面上输入一个字符串,提交到
Servlet
,并调用
EJB
,最后在一个页面上输出处理后的字符串。
工具:
JBOSS 4.2GA + Eclipse 3.2.2 +MyEclipse 5.5GA + JDK 1.6
首先需要搭建好各种环境,这一步比较简单,就不再赘述。唯一需要注意的是在启动
JBOSS
服务器时可能会出现一些问题。如端口号被占用而导致服务器无法启动。如果出现这个问题可以在
%JBOSS%/server/default/deploy/jboss-web.deployer/
目录下找到
server.xml
文件,修改
<Connector port="8080" address="${jboss.bind.address}"
maxThreads="250" maxHttpHeaderSize="8192"
emptySessionPath="true" protocol="HTTP/1.1"
enableLookups="false" redirectPort="8443" acceptCount="100"
connectionTimeout="20000" disableUploadTimeout="true" />
中的
port
属性,然后再重新启动服务器。默认端口是
8080
。
JBOSS
自带了
TOMCAT 5.X
,当然也可以使用另外的
Web
服务器,不过后面的程序会稍微有些改动。
环境搭建完成后就需要编写
EJB
代码。一个
EJB
至少需要
3
个类,即
Home
接口、远程接口、实现类。新建一个
EJB Project
,项目名为:
MyFirstEJB.
1
、创建
Home
接口
---HelloHome.java
package com.lovo.interfaces;
public interface HelloHome extends javax.ejb.EJBHome {
public com.lovo.interfaces.Hello create() throws javax.ejb.CreateException,
java.rmi.RemoteException;
}
2
、创建远程接口
---Hello.java
package com.lovo.interfaces;
public interface Hello extends javax.ejb.EJBObject {
public String sayHello(String message) throws java.rmi.RemoteException;
}
3
、创建实现类
---HelloBean.java
package com.lovo.ejb;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
public class HelloBean implements SessionBean {
private SessionContext context;
public HelloBean() {}
public void ejbActivate() throws EJBException, RemoteException {}
public void ejbPassivate() throws EJBException, RemoteException {}
public void ejbRemove() throws EJBException, RemoteException {}
public void ejbCreate() throws CreateException {}
public void setSessionContext(SessionContext newContext)
throws EJBException {
this.context = newContext;
}
public String sayHello(String message){
if(message == null)
message = "";
message = "Hello " + message + "!";
return message;
}
}
其中方法
sayHello
就是我们需要实现的业务。
类建好之后,接下来就需要配置相关的
xml
文件。在该项目下的
META-INF
里新建两个
xml
文件
ejb-jar.xml
和
jboss.xml
。具体配置如下:
ejb-jar.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "
http://java.sun.com/dtd/ejb-jar_2_0.dtd">
<ejb-jar>
<description>
<![CDATA[No Description.]]>
</description>
<display-name>Generated by XDoclet</display-name>
<enterprise-beans>
<session>
<description>
<![CDATA[Description for Hello]]>
</description>
<display-name>Name for Hello</display-name>
<ejb-name>Hello</ejb-name>
<home>com.lovo.interfaces.HelloHome</home>
<remote>com.lovo.interfaces.Hello</remote>
<ejb-class>com.lovo.ejb.HelloBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
</enterprise-beans>
<assembly-descriptor>
</assembly-descriptor>
</ejb-jar>
jboss.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss PUBLIC "-//JBoss//DTD JBOSS 2.4//EN" "
http://www.jboss.org/j2ee/dtd/jboss_2_4.dtd">
<jboss>
<enterprise-beans>
<session>
<ejb-name>Hello</ejb-name>
<jndi-name>ejb/Hello</jndi-name>
</session>
</enterprise-beans>
<resource-managers>
</resource-managers>
</jboss>
使用
XDoclet
来自动生成这些文件还是很方便的,只是同时会生成一些多余的类和代码,需要手动去删除他们。
到这里一个简单的无状态会话
Bean
就完成了,下面就是将他们部署到
Jboss
下面。可以将项目打包成
jar
文件,然后放在
%JBOSS%/server/default/deploy/
目录下,这样就算部署完成。还可以使用
MyEclipse
来帮你进行部署。如果控制台上出现:
01:59:48,640 INFO [EjbModule] Deploying Hello
01:59:48,703 INFO [ProxyFactory] Bound EJB Home 'Hello' to jndi 'ejb/Hello'
01:59:48,703 INFO [EJBDeployer] Deployed:
file:/%jboss%/server/default/deploy/MyFirstEJB.jar/
就表示部署成功。下面我们就可以编写客户端程序来调用该
EJB
。
新建一个
Web
项目,项目名为
testEJB
,里面包含两个
jsp
文件和一个
servlet
。
EJBServlet.java
package com.lovo.servlet;
import java.io.IOException;
import javax.ejb.CreateException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lovo.interfaces.Hello;
import com.lovo.interfaces.HelloHome;
public class EJBServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("gb2312");
String info = request.getParameter("info");
InitialContext context = null;
Hello hello = null;
try
{
context = new InitialContext();
HelloHome home = (HelloHome)context.lookup("ejb/Hello");
hello = home.create();
}
catch (NamingException e)
{
e.printStackTrace();
}
catch (CreateException e)
{
e.printStackTrace();
}
info = hello.sayHello(info);
request.setAttribute("info", info);
request.getRequestDispatcher("message.jsp").forward(request, response);
}
}
从
jsp
页面上获得表单中的字符串,然后将这个字符串传递到
EJB
的会话
Bean
中进行处理。最后将返回的字符串显示在另外一个
JSP
页面上。
index.jsp
<%@ page language="java" isELIgnored="false" pageEncoding="gb2312"%>
<html>
<head>
<title>EJB</title>
</head>
<body>
<form action="servlet" method="post">
<input type="text" name="info" />
<input type="submit" value="
提交
">
</form>
</body>
</html>
message.jsp
<%@ page language="java" isELIgnored="false" pageEncoding="utf-8"%>
<html>
<head>
<title>message</title>
</head>
<body>
<h1>${info }</h1>
</body>
</html>
如果
Web
项目和
EJB
项目在同一服务器中,那么象上面的程序运行是没什么问题的。如果
Web
项目和
EJB
项目不在同一台服务器中,或者同一台服务器中使用的不是
JBOSS
自带的
Tomcat
,那么需要修改一下
servlet:
修改后的
EJBServlet.java
package com.lovo.servlet;
import java.io.IOException;
import java.util.Hashtable;
import javax.ejb.CreateException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lovo.interfaces.Hello;
import com.lovo.interfaces.HelloHome;
public class EJBServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("gb2312");
String info = request.getParameter("info");
InitialContext context = null;
Hello hello = null;
/*********************
添加的代码
*****************************/
Hashtable environment = new Hashtable();
environment.put(Context.INITIAL_CONTEXT_FACTORY,
"org.jnp.interfaces.NamingContextFactory");
environment.put(Context.URL_PKG_PREFIXES,
"org.jboss.naming:org.jnp.interfaces");
environment.put(Context.PROVIDER_URL, "jnp://localhost:1099");
/*********************
**************************************/
try
{
context = new InitialContext(environment);
HelloHome home = (HelloHome) context.lookup("ejb/Hello");
hello = home.create();
}
catch (NamingException e)
{
e.printStackTrace();
}
catch (CreateException e)
{
e.printStackTrace();
}
info = hello.sayHello(info);
request.setAttribute("info", info);
request.getRequestDispatcher("message.jsp").forward(request, response);
}
}
光修改这里还不够,还需要将
%jboss%/client/jbossall-client.jar
和
EJB
项目的
jar
包拷贝到
web
项目中
WEB-INF/lib
目录下。
补充:在
jsp
或
servlet
中调用
EJB
时出现下面错误时:
04:03:33,714 INFO [STDOUT] java.rmi.ServerException: EJBException:; nested exception is:
javax.ejb.EJBException: Invalid invocation, check your deployment packaging, method=public abstract test.ejb.TestEJBInterface test.ejb.TestEJBHome.create() throws javax.ejb.CreateException,java.rmi.RemoteException
解决办法有三种:
1
、编辑
%jboss%/server/default/conf/jboss-service.xml
<mbean code="org.jboss.naming.NamingService"
name="jboss:service=Naming"
xmbean-dd="resource:xmdesc/NamingService-xmbean.xml">
<!-- The call by value mode. true if all lookups are unmarshalled using
the caller's TCL, false if in VM lookups return the value by reference.
-->
<attribute name="CallByValue">false</attribute>
...
</mbean>
将属性
CallByValue
的值改为
true
2
、编辑
%jboss%/server/default/deploy/ear-deployer.xml
<mbean code="org.jboss.deployment.EARDeployer"
name="jboss.j2ee:service=EARDeployer">
<attribute name="Isolated">false</attribute>
<attribute name="CallByValue">false</attribute>
<attribute name="EnablelibDirectoryByDefault">true</attribute>
</mbean>
将属性
Isolated
和
CallByValue
的值改为
true
3
、编辑
%jboss%/server/default/deploy/jboss-web.deployer/META-INF/jboss-service.xml
<attribute name="Java2ClassLoadingCompliance">false</attribute>
<attribute name="UseJBossWebLoader">false</attribute>
将属性
Java2ClassLoadingCompliance
和
UseJBossWebLoader
的值改为
false
,这里默认值一般都是
false
一般情况下,使用第二种方式就可以解决该问题。