网站首页
JSP空间
动态资讯
开源项目
技术文档
资源下载
J2EE资源
客户论坛
在线支付
 
  技术文档>>JAVA>>新手入门>>基础入门>查看文档  
  专稿:实战ejb之三 开发会话bean(有状态会话bean)     
  文章作者:未知  文章来源:水木森林  
  查看:104次  录入:管理员--2007-11-17  
 

实战ejb系列



在以后的日子里,将由jackliu向大家陆续提供一系列ejb教程,有学习ejb的朋友请同步参考ejb相关书籍,实战系列将以例程的方式帮助你理解这些基本的概念,其中将包括:



专稿:实战ejb之三 开发会话bean(有状态会话bean)(图一)
点击查看大图


所有章节完毕后将制作成pdf电子文档,供大家下载。



实战ejb之三 开发会话bean(有状态会话bean)


会话bean可以分为有状态会话bean(stateful bean)和无状态会话bean(stateless bean),有状态会话bean可以在客户访问之间保存数据,而无状态会话bean不会在客户访问之间保存数据。两者都实现了javax.ejb.sessionbean接口,ejb容器区通过部署文件ejb-jar.xml来判断是否为一个sessionbean提供保存状态的服务,另外,在程序实现上,无状态bean不能声明实例变量,每个方法只能操作方法传来的参数,如果需要在引用期间维持一些数据状态,以在其他方法中可以引用,则可以把bean设计成有状态会话bean。在第二节中我们用一个satatelessdate
bean例子描述了开发无状态会话bean的过程及特性,下面的一节将介绍关于有状态会话bean的一些特性和寿命周期,并用一个例子来证明这些特性。


在本节中你将了解到:



  • 什么是有状态session bean?
  • 有状态session bean寿命周期
  • 编写一个有状态session bean程序
  • 部署到应用服务器
  • 开发和部署测试程序
  • 运行测试程序

什么是有状态session bean?


有状态会话bean(stateful session bean)就是在客户引用期间维护bean中的所有实例数据的状态值,这些数据在引用期间可以被其他方法所引用,其他客户不会共享同一个session
bean的实例。bean的状态被保存到临时存储体中,因为bean是可以被序列化的,所以同样也可以把一个bean状态保存到文件系统或数据库中。因为在调用方法时需要维护状态(这部分是有开销的),所以只有需要维护客户状态时才使用有状态会话bean。典型的会话bean是购物车,当一个客户第一次打开购物车时,系统为他分配一个购物车的会话bean,在以后,每当客户选购了商品将改变购物车的商品记录,而这些记录数据将保存到用户会话数据中。


有状态session bean寿命周期


有状态session bean寿命周期由容器控制,bean的客户并不实际拥有bean的直接引用,当我们部署一个ejb时,容器会为这个bean分配几个实例到组件池(component
pooling)中,当客户请求一个bean时,j2ee服务器将一个预先被实例化的bean分配出去,在客户的一次会话里,可以只引用一次bean,就可以执行这个bean的多个方法。如果又有客户请求同样一个bean,容器检查池中空闲的bean(不在方法中或事务中,如果一个客户长时间引用一个bean但执行一个方法后需要等待一段时间再执行另一个方法,则这段时间也是空闲的),如果全部的实例都已用完则会自动生成一个新的实例放到池中,并分配给请求者。当负载减少时,池会自动管理bean实例的数量,将多余的实例从池中释放。


有状态会话bean的寿命周期比无状态会话bean更加的复杂,有状态会话bean有四种状态:



  1. 不存在
  2. 方法现成
  3. 事务中方法现成
  4. 钝化

如图3-1所示:



专稿:实战ejb之三 开发会话bean(有状态会话bean)(图二)


<图3-1>


有状态会话bean的初始化状态为不存在,当有客户引用一个bean时,按照顺序调用newinstance()、setsessioncontext()和ejbcreate()方法,与第一节中讲到的无状态调用顺序相同。当处于方法现成状态时,如果客户调用remove()方法,则回到不存在状态,并触发bean的ejbremove()方法。如果客户长时间不调用bean或服务器准备释放一些内存资源,则容器将这些bean从组件池中钝化,钝化过程容器将调用bean的ejbpassivate()方法,使程序员有机会在钝化bean时释放分配的资源。当一个客户请求一个被钝化的bean时,容器可以激活bean,激活过程容器将调用ejbactivate()放,使程序员有机会在bean转到方法现成状态时分配bean所需的资源。


bean本身可以管理事务(bmt bean-managed transactions),也可以由容器管理事务(cmt container-managed
transation)。对于cmt,容器在方法开始时打开事务,在方法结束时实现事务。bean开发人员可以通过afterbegin()、beforecompletion()、aftercompletion(boolean)来获取事务的各个状态,如果aftercompletion(boolean)中boolean变量为true表示事务完成,为false表示事务被撤消。


编写一个有状态session bean程序


假设这次我们要为一个基金组织编写一个基金帐户的bean组件,这个组件将为基金管理系统提供一个基金帐户的基本功能。为了能够描述清楚有状态会话bean的特性,我们将之简化成提供三个业务逻辑接口:addfunds()方法为一个基金帐户添加基金,removefunds()方法从基金帐户中取出基金,方法getbalance()为我们提供一个基金帐户的余额查询。我们为这个bean起名为statefulaccount


设计一个有状态的session bean至少包括四个步骤:



  1. 开发主接口
  2. 开发组件接口
  3. 开发bean实现类
  4. 编写部署文件

注意:本节假设你使用的windows操作系统。如果使用其他操作系统,可能影响到存储路径和jdk命令,但这与程序代码和部署文件内容无关。


1.开发主接口(statefulaccounthome.java):


是由bean开发人员编写的一个bean的主接口(interface)程序,负责控制bean的生命周期(生成、删除、查找bean)。只需要开发人员给出一个主接口类,类方法的实现由容器来完成。


主接口扩展了javax.ejb.ejbhome接口,参考avax.ejb.ejbhome接口定义如下:





 package javax.ejb;
import java.rmi.remote;
import java.rmi.remoteexception;

public interface ejbhome extends remote{
public abstract ejbmetadata getejbmetadata() throws remoteexception;
public abstract homehandle gethomehandle() throws remoteexception;
public abstract void remove(object obj) throws remoteexception,removeexception;
public abstract void remove(handle handle) throws remoteexception,removeexception;
}




  • 方法getejbmetadata()返回ejbmetadata接口的引用,取得bean的信息,ejbmetadata不是远程接口。这个类扩展了java.io.serializable,所以可序列化,具有序列化的特性

  • 方法gethomehandle()返回主对象的句柄,句柄是主接口statelessaccounthome的持久性引用,这个类扩展了java.io.serializable,所以可序列化,具有序列化的特性,homehandle
    对象可以传递给另一个jvm,且不传递安全信息,这样新的应用可以不使用jndi来查找对象既可以获得这个主接口,并来创建和获得bean实例。
  • 方法remove()用来删除一个bean的实例,对于一个会话bean,执行remove操作将引用的bean返回到池中,由池来管理其生命周期。

一般情况下,习惯将主接口的命名规则规定为<bean-name>home,所以我们把这个主接口类起名为statefulaccounthome


大部分逻辑方法已经被ejbhome定义,在我们要设计的远程主接口中,不必再重新定义。值得注意的是,我们需要为这个接口定义一个create()方法,用来获得一个实例bean的引用,返回的对象类型是组件接口类statefulaccount。与第二节的statelessdatehome类定义基本相同,不同的是create()方法需要一个double类型的fund参数,当客户创建一个bean引用时,我们将通过这个参数初始化基金帐户的余额。fund数值的状态将由容器来维护。


statefulaccounthome.java代码:






import java.rmi.remoteexception;
import javax.ejb.createexception;
import javax.ejb.ejbhome;

public interface statefulaccounthome extends ejbhome{
public statefulaccount create(double fund) throws remoteexception,createexception;
}


假设我们保存到d:ejbstatefulaccountsrcstatefulaccounthome
.java


2.开发组件接口(statefulaccount.java):


当远程用户调用主接口类生成方法(create(double))时,客户要得到一个组件的远程引用,因此ejb容器要求你为这个bean的所有方法提供一个接口类,而类的实现则与远程主接口statefulaccounthome
一样由容器在部署时自动生成。


组件接口扩展了avax.ejb.ejbobject接口,参考avax.ejb.ejbobject接口定义如下:





 package javax.ejb;
import java.rmi.remote;
import java.rmi.remoteexception;

public interface ejbobject extends remote{
public abstract ejbhome getejbhome() throws remoteexception;
public abstract handle gethandle() throws remoteexception;
public abstract object getprimarykey() throws remoteexception;
public abstract boolean isidentical(ejbobject ejbobject) throws remoteexception;
public abstract void remove() throws remoteexception,removeexception;
}




  • 方法getejbhome()返回远程主接口对象的引用
  • 方法gethandle() 当前组件接口对象的句柄,和远程主接口的句柄homehandle一样,这个对象是被序列化的,所以可以保存到本地或通过rmi/iiop协议传输给其他jvm上的客户使用,而免去jndi查找和调用主接口的create方法,只要执行handle.getejbobject()方法即可取得这个bean实例的引用。

  • getprimarykey()方法一般用于entity bean,如果在session bean中调用,抛出java.rmi.remoteexception。
  • 方法isidentical()用于对当前引用的bean实例和另一bean实例进行比较,因为即便是bean实例相同但有可能不是来自同一个引用,不能使用equals()方法。

  • 方法remove() 删除当前引用的bean实例,由容器来决定是否真的释放气内存,通常会返换到组件池中。注意删除之后要将对象的引用指向为null。


一般情况下,习惯将组件接口的命名规则规定为<bean-name>,所以我们把这个组件接口类起名为statefulaccount


大部分逻辑方法已经被ejbobject 定义,在我们要设计的组件接口statefulaccount中,不必再重新定义,只要我们重申组件中有关业务逻辑的接口即可。为了使远程客户能够得到基金帐户的业务方法,我们必须对应bean的实现类申明业务逻辑接口的方法。方法addfunds(double)向一个帐户增加基金,removefunds(double)方法从一个帐户中取出基金,getbalance()方法得到当前基金帐户的余额,注意这些类都被声名成接口方法,不需要我们在此实现。


在方法addfunds和removefunds中,如果参数不符合要求,抛出insufficientfundexception异常错误。


statefulaccount.java代码:






import javax.ejb.ejbobject;
import java.rmi.remoteexception;

public interface statefulaccount extends ejbobject{
public void addfunds(double fund)
throws remoteexception,insufficientfundexception;
public void removefunds(double fund)
throws remoteexception,insufficientfundexception;
public double getbalance()
throws remoteexception;
}


假设我们保存到d:ejbstatefulaccountsrcstatefulaccount
.java


insufficientfundexception.java代码:






public class insufficientfundexception extends java.lang.exception{
public insufficientfundexception(){super();}
public insufficientfundexception(string msg){super(msg);}
}


假设我们保存到d:ejbstatefulaccountsrcinsufficientfundexception
.java


3.开发bean实现类(statefulaccountejb.java):


这个类包含了业务逻辑的所有详细设计细节。会话bean的实现类实现了(implements)javax.ejb.sessionbean所定义的接口,首先我们先熟悉一下sessionbean的定义:





package javax.ejb;
impot java.rmi.remoteexception;

public interface sessionbean extends enterprisebean{
public void setsessioncontext(sessioncontext ctx) throws ejbexception,remoteexception;
public void ejbremove() throws ejbexception,remoteexception;
public void ejbactivae()throws ejbexception,remoteexception;
public void ejbpassivate()throws ejbexception,remoteexception;
}



容器通过这些方法将相关信息通知给bean实例,所有的方法都抛出removeexception方法是为了与1.0规范兼容,之后版本编写的bean只需要抛出ejbexception即可。


setsessioncontext()方法将会话的语境放到对象变量中,容器在结束会话bean或自动超时死亡之前将会自动调用ejbremove()方法,所以在此可以填入用来释放某些资源的代码。当实例被钝化或被激活时,调用ejbactivae()和ejbpassivate()方法。在钝化过程之前,容器调用ejbpassivate()方法,bean的开发人员可以在这个方法里释放占用的资源,待bean被激活时,在ejbpassivate()方法中再分配这些资源。


一般情况下,习惯将组件实现类的命名规则规定为<bean-name>ejb,所以我们把这个组件类起名为statefulaccountejb


类statefulaccountejb声明要实现sessionbean的定义,所以,我们必须完全实现sessionbean的接口定义。


statefulaccountejb.java代码:






import javax.ejb.*;

public class statefulaccountejb implements sessionbean{
public void ejbcreate(double fund)throws createexception{
if (fund<0)
throw new createexception("invalid fund");
this.fundbalance=fund;
}

public void ejbremove(){}
public void ejbactivate(){}
public void ejbpassivate(){}
public void setsessioncontext(sessioncontext ctx){}

//实例变量,有状态的会话bean将在组件池中维护这个实例的值
private double fundbalance;

//向基金帐户增加基金
public void addfunds(double fund)throws insufficientfundexception{
if (fund<0)
throw new insufficientfundexception("invalid fund");
this.fundbalance+=fund;
}

//从基金帐户撤除部分基金
public void removefunds(double fund)throws insufficientfundexception{
if(fund<0)
throw new insufficientfundexception("invalid fund");
if(this.fundbalance<fund)
throw new insufficientfundexception("the balance less than fund");
this.fundbalance-=fund;
}

//得到基金帐户的余额
public double getbalance(){
return this.fundbalance;
}
}


假设我们保存到d:ejbstatefulaccountsrcstatefulaccountejb
.java


到此为止我们的bean程序组件已经编写完毕了,使用如下命令进行编译:





cd beanstatefulaccount
mkdir classes
cd src
javac -classpath %classpath%;../classes -d ../classes insufficientfundexception.java
statefulaccount.java statefulaccounthome.java statefulaccountejb.java


如果顺利你将可以在..statefulaccountclasses目录下发现有四个类文件。


4.编写部署文件:


一个完整的ejb是由java类和一个描述其特性的ejb-jar.xml文件组成,部署工具将根据这些文件部署到容器中,并自动生成容器所需的残根类。


按照下面个格式编写一个ejb-jar.xml文件,对于dtd介绍此处省去。


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>
this is statefulaccount ejb example
</description>
<display-name>statefulaccountbean</display-name>
<enterprise-beans>
<session>
<display-name>statefulaccount</display-name>
<ejb-name>statefulaccount</ejb-name>
<home>statefulaccounthome</home>
<remote>statefulaccount</remote>
<ejb-class>statefulaccountejb</ejb-class>
<session-type>stateful</session-type>
<transaction-type>container</transaction-type>
</session>
</enterprise-beans>
</ejb-jar>


假设我们保存到d:ejbstatefulaccountclassesmeta-infejb-jar.xml(注意meta-inf必须大写)


现在让我们看看当前的目录结构:





statefulaccount <文件夹 designtimesp=22185>
classes<文件夹 designtimesp=22187>
meta-inf<文件夹 designtimesp=22189>

ejb-jar.xml
insufficienfundexception.class
statefulaccount .class
statefulaccount ejb.class
statefulaccount home.class
src<文件夹 designtimesp=22197>
insufficientfundexception.java
statefulaccount.java
statefulaccountejb.java
statefulaccounthome.java



部署到应用服务器


在部署之前我们需要将这些类文件和xml文件做成一个jar文件,ejb jar文件代表一个可被部署的jar库,在这个库里,包含了服务器代码与ejb模块的配置。ejb-jar.xml文件被放置在jar文件所指定的meta-inf目录中。我们可以使用如下命令得到ejb
jar文件:





cd d:ejbstatefulaccountclasses    (要保证类文件在这个目录下,且有一个meta-inf子目录存放ejb-jar.xml文件)
jar -cvf statefulaccount.jar *.*


确保statefulaccount.jar文件包括的文件目录格式如下:





meta-inf<文件夹 designtimesp=22233>
ejb-jar.xml
insufficientfundexception.class
statefulaccount.class
statefulaccountejb.class
statefulaccounthome.class


部署工具一般由java应用服务器的制造商提供,在这里我使用了apusic应用服务器,并讲解如何在apusic应用服务器部署这个statefulaccount组件。


注意,如果使用其他部署工具,原理是一样的。要使用apusic应用服务器,可以到www.apusic.com上下载试用版。


确定你的apusic服务器已经被启动。 打开"部署工具"应用程序,点击文件->新键工程:


第一步:选择"新建包含一个 ejb组件打包后的ejb-jar模块"选项


第二步:选择一个刚才我们生成的statefulaccount.jar文件


第三步:输入一个工程名,可以随意,这里我们输入statefulaccount


第四步:输入工程存放的地址,这里我们假设被存放到d:ejbstatefulaccountdeploy目录下


完成四个步骤后,如果没有问题将出现statefulaccountbean的部署界面,基本的参数配置已经在我们刚才编写的ejb-jar.xml中定义,可以点击部署->部署到apusic应用服务器完成部署工作。


开发和部署测试程序


sessionbean组件是没有任何运行界面的,组件的实例被容器所管理,所以我们要测试这个bean组件,需要写一段测试程序,这里,我们写一段小服务程序(java
servlet)。


关于如何编写servlet我们这里不做介绍。initialcontext 对象用来获取当前servlet小应用程序的语境,方法lookup从组件池中查找一个jndi对象,并取得一个远程主接口的引用。java:comp/env/ejb/statefulaccount是我们刚才部署statefulaccount组件的jndi名,请参考ejb-jar.xml中的项。要注意的是,lookup()方法返回的是一个object类型的远程主接口对象的残根,为此需要使用javax.rmi.portableremoteobject的narrow()方法来获取一个具体的对象引用,narrow()方法:第一个参数是lookup()方法返回的对象,第二个参数是要得到的引用类型。我们通过narrow()方法并经过造型得到了一个statefulaccounthome对象的实例引用,调用create()方法获取一个statefulaccount组件接口的实例引用,然后就可以与本地一样去引用这个实例。使用完毕后不要忘记将实例的引用指向一个null。
在create方法中,我们为基金帐户初始化一个数值,通过引用,把这个值传递给statefulaccountejb中定义的fundbalanced对象,注意这个对象的状态由容器维护。通过addfund、removefund和getbalance方法我们可以测试fundbalanced状态改变所带来的影响。


下面是提供的代码:


statefulaccountservlet.java文件:






import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import javax.ejb.*;
import javax.naming.initialcontext;

public class statefulaccountservlet extends httpservlet{
public void service(httpservletrequest req,httpservletresponse res) throws ioexception {
res.setcontenttype("text/html");
printwriter out =res.getwriter();
out.println("<html><head><title>statefulaccountservlet</title></head>");
out.println("<body><h2>test result:<hr>");
try{
initialcontext ctx =new initialcontext();
object objref =ctx.lookup("java:comp/env/ejb/statefulaccount");
statefulaccounthome home=(statefulaccounthome)
javax.rmi.portableremoteobject.narrow(
objref,statefulaccounthome.class);

//得到一个基金帐户对象的引用,并初始化帐户金额为100000
statefulaccount bean=home.create(100000);
out.println("the account balance:"+bean.getbalance()+"<br>");
//向基金帐户增加5000.25
bean.addfunds(5000.25);
out.println("method of addfunds(5000.25) result:"+bean.getbalance()+"<br>");
//从基金帐户调出1000.02
bean.removefunds(1000.02);
out.println("method of removefunds(1000.02) result:"+bean.getbalance());
out.println("<hr>");
out.println("current account balance:"+bean.getbalance());

bean=null;

}catch(javax.naming.namingexception ne){
out.println("naming exception caught:"+ne);
ne.printstacktrace(out);
}catch(javax.ejb.createexception ce){
out.println("create exception caught:"+ce);
ce.printstacktrace(out);
}catch(java.rmi.remoteexception re){
out.println("remote exception caught:"+re);
re.printstacktrace(out);
}catch(insufficientfundexception ie){
out.println("insufficientfund exception caught:"+ie);
ie.printstacktrace(out);
}
out.println("</body></html>");
}
}


假设我们将文件保存到d:ejbstatefulaccountsrcstatefulaccountservlet.java


使用如下命令编译servlet





cd d:ejbstatefulaccount
mkdir test
cd test
mkdir web-inf
cd web-inf
mkdir classes
cd d:ejbstatefulaccountsrc
javac -classpath %classpath%;../classes/ -d ../test/web-inf/classes statefulaccountservlet.java



编译成功后将这个servlet部署到与statefulaccount同一工程中,在部署前需要我们为部署编写一个web.xml,并制作web模块文件(war文件),其中告诉部署工具这个servlet需要参考的一些资源和部署信息,这里我们将定义一个jndi参考:





  <ejb-ref>
<description></description>
<ejb-ref-name>ejb/statefulaccount</ejb-ref-name>
<ejb-ref-type>session</ejb-ref-type>
<home>statefulaccounthome</home>
<remote>statefulaccount</remote>
<ejb-link>statefulaccount</ejb-link>
</ejb-ref>



<ejb-ref-name>告诉部署工具,这个web模块需要参考的资源jndi名称,被指定参考一个sessionbean组件。
web.xml文件内容如下:





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

<!doctype web-app public '-//sun microsystems, inc.//dtd web application 2.3//en' 'http://java.sun.com/dtd/web-app_2_3.dtd'>

<web-app>
<icon>
<small-icon></small-icon>
<large-icon></large-icon>
</icon>
<display-name>statefulaccount</display-name>
<description></description>
<context-param>
<param-name>jsp.nocompile</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>jsp.usepackages</param-name>
<param-value>true</param-value>
<description></description>
</context-param>
<ejb-ref>
<description></description>
<ejb-ref-name>ejb/statefulaccount</ejb-ref-name>
<ejb-ref-type>session</ejb-ref-type>
<home>statefulaccounthome</home>
<remote>statefulaccount</remote>
<ejb-link>statefulaccount</ejb-link>
</ejb-ref>

</web-app>


假设我们将文件保存到d:ejbstatefulaccount estweb-infweb.xml


下面我们要部署这个servlet到j2ee服务器。j2ee web应用可以包括java servlet类、javaserver page组件、辅助的java类、html文件、媒体文件等,这些文件被集中在一个war文件中。其中war结构具有固定的格式,根目录名为web-inf,同一目录下应该有一个web.xml文件,用来描述被部署文件的部署信息,jsp、html等文件可以放置在这个目录下,同时web-inf目录下可能存在一个classes目录用于存放servlet程序,如果引用了一些外部资源,则可以被放置到web-inflib目录下。使用下面的命令生成这个servlet测试程序的war文件:





cd d:ejbstatefulaccount	est
jar -cvf statefulaccount.war *.*



确保statefulaccount.war文件包括的文件目录格式如下:





web-inf<文件夹 designtimesp=22451>
classes<文件夹 designtimesp=22453>

statefulaccountservlet.class
web.xml


成功编译后,将这个servlet一同部署到statefulaccount工程中,我们回到"部署工具",点击编辑-->填加一个web模块,选择我们刚刚编译成的statefulaccount.war文件
点击部署->部署到apusic应用服务器完成部署工作。


运行测试程序


打开浏览器,在浏览器中输入:





http://localhost:6888/statefulaccount/servlet/statefulaccountservlet
localhost-web server的主机地址
:6888-应用服务器端口,根据不同的应用服务器,端口号可能不同
/statelessfulaccount-部署servlet时指定的www根路径值
/servlet-ejb容器执行servlet的路径
/statefulaccountservlet-测试程序


如果运行正常应该能够看到下面的结果


 



专稿:实战ejb之三 开发会话bean(有状态会话bean)(图三)


<图3-2>

 
 
上一篇: 专稿:实战ejb之二 开发会话bean(无状态会话bean)    下一篇: 专稿:实战ejb之四 开发实体cmp(ejb 1.1规范)
  相关文档
hibernate 的原理与配置快速入门 11-17
sun将升级高端unix服务器 ultrasparc 11-17
基于nokia s40的猜数字游戏之一 11-17
独家专访袁红岗:谈jsf的未来之路(上篇) 11-17
轻松架起java连接com对象的桥梁 11-16
java入门教程:第一章 11-17
部署描述符(web.xml)元素---[en ed] 11-17
java开发中的中文处理问题 11-16
jformattedtextfield和格式化输入 11-17
jvm的垃圾回收机制详解和性能调优 11-17
保护您的 j2me/midp 应用程序 11-17
j2ee的核心api与组件 11-17
java ee 5规范横空出世 11-17
利用java applet 编程实现动画特技 11-17
一个进行base64编码的类 11-17
jsp页面中限制对 web 资源的访问 11-17
使用ejb组件你需要了解些什么呢? 11-17
java理论和实践:用软引用阻止内存泄漏 11-16
通过---java程序--打开文本! 11-17
全面挖掘javaexcelapi使用方法 11-17
返回首页 | 关于我们 | J网章程 | JSP空间合租 | 客服中心 | 免责声明 | 常见问题 | 参观机房
本站主机空间代理至厦门市华众网络科技有限公司
《中华人民共和国增值电信业务经营许可证》
编号:闽B2-20050079
@2005-2008福建JSP技术网 版权所有 闽ICP备05000928号
技术电话:13616026886
邮箱:admin@fjjsp.com 站长QQ,点击这里给我发消息