首页 / 软件开发 / JAVA / 循速渐进学用Session Bean(五)
循速渐进学用Session Bean(五)2008-05-07创建一个实用的Session BeanHelloWorldSession例子的主要目的是帮助你熟悉一个session bean的整体结构。现在你已经熟悉了session bean的结构,你可以写一个更实用的bean了。特别地,你可以写一个由数据库中接收数据的bean。以下的例子,假定你拥有一个SQL表格,里面包含有产品的代码和价格,你也可以使用以下SQL命令建立它:create table price
(product_code varchar(10) not null primary key,
price decimal(10,2) not null)
Pricing session bean可以列出全部有效的产品代码,并且可以返回某个产品代码的价格,该代码由Remote接口指定,如6.9列表所示:Listing 6.9 Source Code for Pricing.java
package usingj2ee.pricing;
import java.rmi.*;
import javax.ejb.*;
/** Defines the methods you can call on a Pricing session */
public interface Pricing extends EJBObject
{
/** Returns all the available product codes */
public String[] getProductCodes() throws RemoteException;
/** Returns the price for a specific product code */
public double getPrice(String productCode)
throws RemoteException, InvalidProductCodeException;
}
Pricing session bean并不需要记得某个客户的任何信息,所以可以用一个无状态的session bean实现。PricingHome接口如列表6.10所示,它仅需要一个create方法。Listing 6.10 Source Code for PricingHome.java
package usingj2ee.pricing;
import java.rmi.*;
import javax.ejb.*;
/** Defines the methods for creating a Pricing session */
public interface PricingHome extends EJBHome
{
/** Creates a Pricing session bean */
public Pricing create() throws RemoteException, CreateException;
}
当一个session bean需要访问一个数据库连接时,它通常在setSessionContext方法中分配一个连接,最后在ejbRemote方法中释放它。当然,如果你拥有一个数据库的连接,在容器调用ejbPassivate方法时,你必须准备关闭它,在容器调用ejbActivate时,重新得到连接。你将会发现大部分的EJB开发者使用一个方法来返回一个连接;这样你就以后就可以修改得到连接的方法,而不会影响使用这些连接的代码。你也应该使用DataSource对象来创建连接。DataSource让修改数据库的驱动变得容易,并且可以在需要的时候使用连接池。列表6.11展示了Pricing session bean的实现类PricingImplListing 6.11 Source Code for PricingImpl.java
package usingj2ee.pricing;
import java.rmi.*;
import java.util.*;
import javax.ejb.*;
import java.sql.*;
import javax.sql.*;
import javax.naming.*;
/** The implementation class for the Pricing bean */
public class PricingImpl implements SessionBean
{
/** The session context provided by the EJB container. A session bean must
hold on to the context it is given. */
private SessionContext context;
/** The database connection used by this session */
private Connection conn;
/** An EJB must have a public, parameterless constructor */
public PricingImpl()
{
}
/** Called by the EJB container to set this session"s context */
public void setSessionContext(SessionContext aContext)
{
context = aContext;
}
/** Called by the EJB container when a client calls the create() method in
the Home interface */
public void ejbCreate()
throws CreateException
{
try
{
// Allocate a database connection
conn = getConnection();
}
catch (Exception exc)
{
throw new CreateException(
"Unable to access database: "+exc.toString());
}
}
/** Called by the EJB container to tell this session bean that it is being
suspended from use (it"s being put to sleep). */
public void ejbPassivate()
throws EJBException
{
try
{
// Shut down the current database connection
conn.close();
conn = null;
}
catch (Exception exc)
{
throw new EJBException("Unable to close database connection: "+
exc.toString());
}
}
/** Called by the EJB container to wake this session bean up after it
has been put to sleep with the ejbPassivate method. */
public void ejbActivate()
throws EJBException
{
try
{
// When the bean wakes back up, get a database connection again
conn = getConnection();
}
catch (Exception exc)
{
throw new EJBException(
"Unable to access database: "+exc.toString());
}
}
/** Called by the EJB container to tell this session bean that it has been
removed, either because the client invoked the remove() method or the
container has timed the session out. */
public void ejbRemove()
throws EJBException
{
try
{
// Shut down the current database connection
conn.close();
conn = null;
}
catch (Exception exc)
{
throw new EJBException("Unable to close database connection: "+
exc.toString());
}
}
/** Returns a list of the available product codes */
public String[] getProductCodes()
throws EJBException
{
Statement s = null;
try
{
s = conn.createStatement();
ResultSet results = s.executeQuery(
"select product_code from price");
Vector v = new Vector();
// Copy the results into a temporary vector
while (results.next())
{
v.addElement(results.getString("product_code"));
}
// Copy the vector into a string array
String[] productCodes = new String[v.size()];
v.copyInto(productCodes);
return productCodes;
}
catch (Exception exc)
{
throw new EJBException("Unable to get product codes: "+
exc.toString());
}
finally
{
// Close down the statement in a finally block to guarantee that it gets
// closed, whether an exception occurred or not
try
{
s.close();
}
catch (Exception ignore)
{
}
}
}
/** Gets the price for a particular product code */
public double getPrice(String productCode)
throws EJBException, InvalidProductCodeException
{
PreparedStatement ps = null;
try
{
// It"s always better to use a prepared statement than to try to insert
// a string directly into the query string. This way you don"t have to
// worry if there"s a quote in the product code
ps = conn.prepareStatement(
"select price from price where product_code = ?");
// Store the product code in the prepared statement
ps.setString(1, productCode);
ResultSet results = ps.executeQuery();
// If there are any results, get the first one (there should only be one)
if (results.next())
{
return results.getDouble("price");
}
else
{
// Otherwise, if there were no results, this product code doesn"t exist
throw new InvalidProductCodeException(productCode);
}
}
catch (SQLException exc)
{
throw new EJBException("Unable to get price: "+
exc.toString());
}
finally
{
// Close down the statement in a finally block to guarantee that it gets
// closed, whether an exception occurred or not
try
{
ps.close();
}
catch (Exception ignore)
{
}
}
}
protected Connection getConnection()
throws SQLException, NamingException
{
// Get a reference to the naming service
InitialContext context = new InitialContext();
// Get the data source for the pricing database
DataSource ds = (DataSource) context.lookup(
"java:comp/env/jdbc/PriceDB");
// Ask the data source to allocate a database connection
return ds.getConnection();
}
}