J2ee应用程序设计――多层框架

本人从事j2ee的设计已又多年,对j2ee框架,和其设计模式有较深,以下是我在开发过程中提出的一个框架,供大家参考,此框架使用以下设计模式:session façade,general Attibute method,jdbc for reading,business delegate,home factory,data access command bean 综述 关于j2ee的框架设计的中心思想是:one transaction ,one invocation,,现今很多相应的设计思想和模式都是基于此。这个思想将贯穿于这个文章中,为了做到高性能,可复用性,可扩展性,将其框架分为五层:persistence 层,domain层,server 层,aplication 层,presentation 层,以下我将对各层做相应的阐述,并用wsad做一个实例,以供大家查考。 persistence 层 作用:用于访问底层资源,提供公共接口,例如javamail,jms等,以下以连接池为例 模型:data access command bean 建立一些用于与连接池打交道的class,将domain层与数据库隔离。 相应操作:(使用wsad) 打开java perspective,在ejbmodel目录下建立一个package,命名为com.aostar.persisitence 在相应的package里建立一个新的class,命名为DataBase.class,用于取得连接 编写代码如下: package com.aostor.persistence; import java.sql.Connection; import javax.naming.Context; import javax.naming.InitialContext; import javax.sql.DataSource; public class Database { public static Connection getConnection() throws Exception { Context ctx=null; Try { ctx=new InitialContext(); DataSource dt=(DataSource)ctx.lookup("jdbc/template"); return dt.getConnection(); } catch(Exception ex) { ex.printStackTrace(); throw new Exception("the class of Database error:"+ex.toString()); } finally { if(ctx!=null) { try { ctx.close(); } catch(Exception ex) { } ctx=null; } } } } 然后做一个dacb,建立新class,DataAccessBean,采用的模型:proxy model,代码如下 package com.aostor.persistence; import java.math.BigDecimal; import java.sql.Array; import java.sql.Blob; import java.sql.Clob; import java.sql.Connection; import java.sql.Date; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Time; import java.sql.Timestamp; public class DataAccessBean { /** * variebles * */ String sql=""; String jdbcName=Database.Oracle; Connection con=null; PreparedStatement pstt=null; /** * setSql * * @param value String */ public void setSql(String value) throws NotConnectionException { try { if(con==null) { con=Database.getConnection(jdbcName); } sql=value; pstt=con.prepareStatement(value,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY); } catch(Exception ex) { ex.printStackTrace(); throw new NotConnectionException(Database.Oracle+"can't be connection"); } } /** * setSql * * @param value String * @param resultSetType int * @param resultSetCurrent int */ public void setSql(String value,int resultSetType,int resultSetCurrent) throws NotConnectionException { try { if(con==null) { con=Database.getConnection(jdbcName); } sql=value; pstt=con.prepareStatement(value,resultSetType,resultSetCurrent); } catch(Exception ex) { ex.printStackTrace(); throw new NotConnectionException(Database.Oracle+"can't be connection"); } } /** * close * */ public void close() throws NotCloseException { if(pstt!=null) { try { pstt.close(); } catch(Exception ex) { ex.printStackTrace(); throw new NotCloseException(ex.toString()); } pstt=null; } if(con!=null) { try { con.close(); } catch(Exception ex) { ex.printStackTrace(); throw new NotCloseException(ex.toString()); } con=null; } sql=""; } /** * setJdbcName * @param jdbcName String */ public void setJdbcName(String jdbcName) { if(con!=null) { try { close(); } catch(NotCloseException ex) { } } this.jdbcName=jdbcName; } /** * setString * @param value String * @param col,int */ public void setString(int col,String value) { try { pstt.setString(col,value); }catch(SQLException ex){ } } /** * setInt * @param value int * @param col int */ public void setInt(int col,int value){ try{ pstt.setInt(col,value); }catch(SQLException ex){ } } /** * setFloat * @param value Float * @param col int */ public void setFloat(int col,float value){ try{ pstt.setFloat(col,value); }catch(SQLException ex){ } } /** * setDouble * @param value Double * @param col int */ public void setDouble(int col,double value){ try{ pstt.setDouble(col,value); }catch(SQLException ex){ } } /** * setLong * @param value long * @param col int */ public void setLong(int col,long value){ try{ pstt.setLong(col,value); }catch(SQLException ex){ } } /** * setByte * @param value byte * @param col int */ public void setByte(int col,byte value){ try{ pstt.setByte(col,value); }catch(SQLException ex){ } } /** * setBytes * @param value byte[] * @param col int */ public void setBytes(int col,byte[] value){ try{ pstt.setBytes(col,value); }catch(SQLException ex){ } } /** * setShort * @param value Short * @param col int */ public void setShort(int col,short value){ try{ pstt.setShort(col,value); }catch(SQLException ex){ } } /** * setBigDecimal * @param value BigDecimal * @param col int */ public void setBigDecimal(int col,BigDecimal value){ try{ pstt.setBigDecimal(col,value); }catch(SQLException ex){ } } /** * setBoolean * @param value boolean * @param col int */ public void setBoolean(int col,boolean value){ try{ pstt.setBoolean(col,value); }catch(SQLException ex){ } } /** * setDate * @param value Date * @param col int */ public void setDate(int col,Date value){ try{ pstt.setDate(col,value); }catch(SQLException ex){ } } /** * setTime * @param value Time * @param col int */ public void setTime(int col,Time value){ try{ pstt.setTime(col,value); }catch(SQLException ex){ } } /** * setTimestamp * @param value Timestamp * @param col int */ public void setTimestamp(int col,Timestamp value){ try{ pstt.setTimestamp(col,value); }catch(SQLException ex){ } } /** * setClob * @param value Clob * @param col int */ public void setClob(int col,Clob value){ try{ pstt.setClob(col,value); }catch(SQLException ex){ } } /** * setBlob * @param value Blob * @param col int */ public void setBlob(int col,Blob value){ try{ pstt.setBlob(col,value); }catch(SQLException ex){ } } /** * setObject * @param value int * @param col int */ public void setObject(int col,Object value){ try{ pstt.setObject(col,value); }catch(SQLException ex){ } } /** * setArray * @param value Array * @param col int */ public void setArray(int col,Array value){ try{ pstt.setArray(col,value); }catch(SQLException ex){ } } /** * setNull * @param value int * @param col int */ public void setNull(int col,int value){ try{ pstt.setNull(col,value); }catch(SQLException ex){ } } /** * getMetaData * @return MetaData */ public ResultSetMetaData getMetaData() throws SQLException{ try{ return pstt.getMetaData(); }catch(SQLException ex){ throw ex; } } /** * execute */ public boolean execute() throws SQLException{ try{ doLog(); return pstt.execute(); }catch(SQLException ex){ doError(); ex.printStackTrace(); throw ex; } } /** * executeQuery */ public ResultSet executeQuery() throws SQLException{ try{ doLog(); return pstt.executeQuery(); }catch(SQLException ex){ doError(); ex.printStackTrace(); throw ex; } } /** * executeUpdate */ public int executeUpdate() throws SQLException{ try{ doLog(); return pstt.executeUpdate(); }catch(SQLException ex){ doError(); ex.printStackTrace(); throw ex; } } /** * doLog */ void doLog(){ } /** * doError() */ void doError(){ } } 两个异常: package com.aostor.persistence; public class NotCloseException extends Exception { /** * Constructor for NotCloseException */ public NotCloseException() { super(); } /** * Constructor for NotCloseException */ public NotCloseException(String arg0) { super(arg0); } } package com.aostor.persistence; public class NotConnectionException extends Exception { /** * Constructor for NotConnectionException */ public NotConnectionException() { super(); } /** * Constructor for NotConnectionException */ public NotConnectionException(String arg0) { super(arg0); } } 在sever perspective中建立连接池 打开服务器配置文件,sever-cfg.xml 选定视图界面中Data source 以下以oralce为例 先建立jdbc driver Name:OracleIdbcDriver Description:Oracle9i JDBC Driver 前两项为名称和描述,可随意配置 Implementation class name oracle.jdbc.pool.OracleConnectionPoolDataSource URL prefix:jdbc:oracle:thin Class:c:/oracle/ora92/jdbc/lib/classes12.zip 然后建立Data Source Name:Session Persistence Datasource JNDI name:jdbc/template Database name:ao8226 Default user id:feinst Default user user password:* 其他缺省,或为空 最后建立resource property name:URL (大写) Type:java.lang.String Value:jdbc:oracle:thi:@ao-8226(服务器名称):1521:ao8226(数据库名) Description : 说明:此层可由专人写出,打包,以后,由各位导入既可,但连接池必须自己配置,可方便大家做模块测试之用. Database JDBC Driver Oracle 8i Oracle Thin Driver Version 8.1.6.0.1Merant DataDirect Oracle Driver 2.2 Oracle 9i Oracle Thin Driver Version 8.1.7 Microsoft SQL Server 7.0 Merant DataDirect SQL Server Driver 2.2JTurbo SQL Server Driver 2.0i-Net Sprinta 4.15 SQL Server Driver MySQL Max 3.23.48 mm.mysql 2.0.4 Informix 7.3.0 TC3 Informix JDBC Driver for Informix Dynamic Server 2.10.JC1N361Merant DataDirect Informix Driver 2.2 Cloudscape 4.0 Cloudscape 4.0 JDBC Driver 4.0Cloudscape 4.0 RMI JDBC Driver 4.0 MySQL 3.28 with InnoDB tables MySQL 2.0.4 driver Sybase 12.5 jConnect for JDBC 5.5 以上为其他数据的jdbc引擎,配置基本相同 domain层 此层主要是用一些bmp或cmp封装usercase的buisness thing,至于选用何种bean,视情况而定, 一般来说,当数据库的table已存在,大多用bmp, bmp 其命名规则如下: com.模块名称.domain.bean名称 进入j2ee perspective, 建立一个新的enterprise bean 编写代码: 考虑到ejb server和container的版本不同,如果是ejb1.x,只写一套接口,如EJBHome和EJBObject的接口,如果是ejb2.0,需写两套接口,EJBHome,EJBObject,和EJBLocalHome, EJBLocalObject接口,两者没有多大的区别,只是前者要抛出RemoteException异常,需要指出的是接口的中的方法不需要自己写,因为可以在其对应的bean中,用工具成生。Bean中method名称前有ejb的为容器调用方法, 代码编写原则是如果method中的放回值和参数,能够用接口的,必须用接口,已方便以后的扩展 如图:(生成Home接口和远端接口) a、 TdomainHome(Home接口) import java.rmi.RemoteException; import javax.ejb.CreateException; import javax.ejb.EJBHome; import javax.ejb.FinderException; /** * Home interface for Enterprise Bean: TDomain */ public interface TDomainHome extends javax.ejb.EJBHome { /** * Creates an instance from a key for Entity Bean: TDomain */ public TDomain create() throws javax.ejb.CreateException, java.rmi.RemoteException; /** * Finds an instance using a key for Entity Bean: TDomain */ public TDomain findByPrimaryKey(TDomainKey primaryKey) throws javax.ejb.FinderException, java.rmi.RemoteException; /** * ejbCreate * @param id String * @param name String * @param birth String * @param sex char * @return TDomainKey */ public TDomain create(String id,String name,String birth,char sex) throws CreateException, java.rmi.RemoteException; } b、 Tdomain(远端接口) import java.rmi.RemoteException; import java.util.HashMap; import javax.ejb.EJBObject; /** * Remote interface for Enterprise Bean: TDomain */ public interface TDomain extends javax.ejb.EJBObject { /** * generic Attribute method * @param Attri hashMap * */ public void changeValue(HashMap attri) throws java.rmi.RemoteException; } c、TDomainBean import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.HashMap; import javax.ejb.CreateException; import javax.ejb.EJBException; import javax.ejb.EntityBean; import javax.ejb.EntityContext; import javax.ejb.FinderException; import javax.ejb.RemoveException; import com.aostor.persistence.Database; /** * Bean implementation class for Enterprise Bean: TDomain */ public class TDomainBean implements javax.ejb.EntityBean { private javax.ejb.EntityContext myEntityCtx; /** * getEntityContext */ public javax.ejb.EntityContext getEntityContext() { return myEntityCtx; } /** * setEntityContext */ public void setEntityContext(javax.ejb.EntityContext ctx) { myEntityCtx = ctx; } /** * unsetEntityContext */ public void unsetEntityContext() { myEntityCtx = null; } /** l ejbActivate l 容器管理bean时,当bean进入活跃时,应做的一些操作 */ public void ejbActivate() { //id在table中对应pk id=((TDomainKey)myEntityCtx.getPrimaryKey()).getValue(); } /** * ejbCreate */ public TDomainKey ejbCreate() throws javax.ejb.CreateException { return null; } /** l ejbFindByPrimaryKey与home接口的findByPriamryKey对应 l 用主键查找bean */ public TDomainKey ejbFindByPrimaryKey(TDomainKey primaryKey) throws javax.ejb.FinderException { DataAccessBean dab=new DataAccessBean(); Try { //connection dab.setSql("select * from template1 where id =? "); dab.setString(1,primaryKey.getValue()); //execute:insert into template (id) values ? ResultSet rs=dab.executeQuery(); rs.next(); id=rs.getString("id"); return primaryKey; } catch(Exception ex) { throw new FinderException("the class of TDomain :"+ex.toString()); } finally { if(dab!=null) { try { dab.close(); } catch(Exception ex) { } dab=null; } } } /** l ejbLoad l bean活跃时应装入的数据项 */ public void ejbLoad() { DataAccessBean dab=new DataAccessBean(); Try { //connection dab.setSql("select * from template1 where id =?"); dab.setString(1,id); //execute:insert into template (id) values ? ResultSet rs=dab.executeQuery(); if(rs.next()) { this.name=rs.getString("name"); this.birth=rs.getString("birth"); this.sex=rs.getString("sex").charAt(0); } else { throw new EJBException("this bean don't exist :id:"+id); } } catch(Exception ex) { ex.printStackTrace(); } finally { if(dab!=null) { try { dab.close(); } catch(Exception ex) { } dab=null; } } } /** l ejbPassivate l bean处于非活跃状态时,应做的操作 */ public void ejbPassivate() { id=null; } /** * ejbPostCreate */ public void ejbPostCreate() throws javax.ejb.CreateException { } /** l ejbRemove l 删除bean,永久删除,不常用 */ public void ejbRemove() throws javax.ejb.RemoveException { DataAccessBean dab=new DataAccessBean(); Try { //connection dab.set("delete from template1 where id =? "); dab.setString(1,id); //execute:insert into template (id) values ? dab.executeUpdate(); } catch(Exception ex) { ex.printStackTrace(); throw new RemoveException("the class of TDomain:"+ex.toString()); } finally { if(dab!=null) { try { dab.close(); } catch(Exception ex){ } dab=null; } } } /** l ejbStore l bean处于非活跃状态时,应将数据项中的指装入数据库或其他可持续的地方 */ public void ejbStore() { DataAccessBean dab=new DataAccessBean(); If(isModified){ Try { //connection dab.setSql("update template1 set name =?,birth =?,sex =? where id =? "); dab.setString(1,name); dab.setString(2,birth); dab.setString(3,String.valueOf(sex)); dab.setString(4,id); //execute:insert into template (id) values ? dab.executeUpdate(); isModified=false; } catch(Exception ex) { ex.printStackTrace(); } finally { if(dab!=null) { try { dab.close(); } catch(Exception ex) { } dab=null; } } } } /** l domains l 数据项,尽量设立缺省值 */ String name="guest"; String id; String birth="20000000"; char sex='f'; boolean isModified=false; /** l ejbPostCreate l 与ejbCreate同时存在,,用于创建, l ejbCreate用于创建新项,ejbPostCreate用与创建后应做的事,有先后顺序 l 与Home接口的Create方法对应, l 注意三者的异常和返回值,一般来说,ejbCreate返回其主键类,Create返回其远端接口,两者除了Create的RemoteException异常外,必须用于相同的异常,其次CreateException必须有 l ejbPostCreate一般没有返回值,没有异常 l 由于container的调用顺序为ejbCreate,ejbPostCreate,Store,所以在生成新项时先要对每一个没有缺省值的数据项设值,特别时主键,要注意此点,否则会出现无法想象的结果 * @param id String * @param name String * @param birth String * @param sex char */ public void ejbPostCreate(String id,String name,String birth,char sex) { } /** * ejbCreate * @param id String * @param name String * @param birth String * @param sex char * @return TDomainKey */ public TDomainKey ejbCreate(String id,String name,String birth,char sex) throws CreateException { DataAccessBean dab=new DataAccessBean(); Try { //set values this.id=id; this.name=name; this.birth=birth; this.sex=sex; //connection dab.setSql("insert into template1 (id) values (?) "); dab.setString(1,id); //execute:insert into template (id) values ? dab.executeUpdate(); return new TDomainKey(id); } catch(Exception ex) { ex.printStackTrace(); throw new CreateException("the class of TDomain :"+ex.toString()); } finally { if(dab!=null) { try { dab.close(); } catch(Exception ex) { } dab=null; } } } /** * Gets the name * @return Returns a String */ public String getName() { return name; } /** * Sets the name * @param name The name to set */ public void setName(String name) { if(this.name.equals(name))isModified=true; this.name = name; } /** * Gets the birth * @return Returns a String */ public String getBirth() { return birth; } /** * Sets the birth * @param birth The birth to set */ public void setBirth(String birth) { if(this.birth.equals(birth))isModified=true; this.birth = birth; } /** * Gets the sex * @return Returns a char */ public char getSex() { return sex; } /** * Sets the sex * @param sex The sex to set */ public void setSex(char sex) { if(this.sex.equals(sex))isModified=true; this.sex = sex; } /** l generic Attribute method l 此处用于修改数据,采用了generic Attribute method 模式,主要是为了减少远端调用并提供了通用的调用方式, * @param Attri hashMap * */ public void changeValue(HashMap attri) { if(attri.containsKey("name")) { setName((String)attri.get("name")); } if(attri.containsKey("sex")) { setSex(((String)attri.get("sex")).charAt(0)); } if(attri.containsKey("birth")) { setBirth((String)attri.get("birth")); } } } d、TdomainKey 在java perspective中,修改TdomainKey 将主键加入到代码中 /** * Key class for Entity Bean: TDomain */ public class TDomainKey implements java.io.Serializable { static final long serialVersionUID = 3206093459760846163L; /** * primary key */ String id; /** * Creates an empty key for Entity Bean: TDomain */ public TDomainKey() { } /** * Creates an empty key for Entity Bean: TDomain */ public TDomainKey(String id) { this.id=id; } /** * Returns true if both keys are equal. */ public boolean equals(java.lang.Object otherKey) { if (otherKey instanceof TDomainKey) { TDomainKey o = (TDomainKey)otherKey; return (id.equals(o.getValue())); } return false; } /** * Return value of primarykey */ public String getValue() { return id; } /** * Returns the hash code for the key. */ public int hashCode() { return (id.hashCode()); } } 部署代码,到j2ee perspective,在ejb项目中,如图操作 部署完成后既可运行发布,并调试代码,需注意的是,服务器可用两种方式启动,一种是正常方式,一种是调试方式(可单步跟踪) 调试需注意:分三步:每个ejb的模块调试,集成调试,系统调试(由专人负责) 模块调试的环境为:客户端测试环境,如图 其调用方法和程序调用相同 绑定name:其步骤,打开ejb extension editor,其绑定的名称为 name:ejb/Tdomain 见图 cmp 首先生成一个enterprise bean,bean type定为cmp,然后加入数据项(需要录入数据库的数据项) 如图:(注意必须设置主键) 输入代码: a、 TdepartmentHome import java.rmi.RemoteException; import javax.ejb.CreateException; import javax.ejb.EJBHome; import javax.ejb.FinderException; /** * Home interface for Enterprise Bean: TDepartment */ public interface TDepartmentHome extends javax.ejb.EJBHome { /** * Creates an instance from a key for Entity Bean: TDepartment */ public TDepartment create(java.lang.String id) throws javax.ejb.CreateException, java.rmi.RemoteException; /** * Finds an instance using a key for Entity Bean: TDepartment */ public TDepartment findByPrimaryKey(TDepartmentKey primaryKey) throws javax.ejb.FinderException, java.rmi.RemoteException; /** l Finds an instance using name for Entity Bean: TDepartment l 注意在设计cmp时,对于finder方法,必须在home写出,然后在ejb 的扩展editor编写其sql语句,而不象bmp需要在bean class中写对应bean 方法,这一点需要注意 */ public Collection findByName(String name) throws javax.ejb.FinderException, java.rmi.RemoteException; /** * ejbCreate * @param id String * @param name String * @param director String * @return TDepartmentKey */ public TDepartment create(String id,String name,String director) throws CreateException, java.rmi.RemoteException; } b、 TDepartmentBean import java.rmi.RemoteException; import java.util.HashMap; import java.util.List; import java.util.Vector; import javax.ejb.CreateException; import javax.ejb.EntityBean; import javax.ejb.EntityContext; import javax.ejb.FinderException; import javax.ejb.RemoveException; import com.ibm.ivj.ejb.associations.interfaces.Link; /** * Bean implementation class for Enterprise Bean: TDepartment */ public class TDepartmentBean implements javax.ejb.EntityBean { private javax.ejb.EntityContext myEntityCtx; /** * Implemetation field for persistent attribute: id */ public java.lang.String id; /** * Implemetation field for persistent attribute: name */ public java.lang.String name; /** * Implemetation field for persistent attribute: director */ public java.lang.String director; /** * getEntityContext */ public javax.ejb.EntityContext getEntityContext() { return myEntityCtx; } /** * setEntityContext */ public void setEntityContext(javax.ejb.EntityContext ctx) { myEntityCtx = ctx; } /** * unsetEntityContext */ public void unsetEntityContext() { myEntityCtx = null; } /** * ejbActivate */ public void ejbActivate() { _initLinks(); } /** * ejbCreate method for a CMP entity bean. */ public TDepartmentKey ejbCreate(java.lang.String id) throws javax.ejb.CreateException { _initLinks(); this.id = id; return null; } /** * ejbLoad */ public void ejbLoad() { _initLinks(); } /** * ejbPassivate */ public void ejbPassivate() { } /** * ejbPostCreate */ public void ejbPostCreate(java.lang.String id) throws javax.ejb.CreateException { } /** * ejbRemove */ public void ejbRemove() throws javax.ejb.RemoveException { try { _removeLinks(); } catch (java.rmi.RemoteException e) { throw new javax.ejb.RemoveException(e.getMessage()); } } /** * ejbStore */ public void ejbStore() { } /** * This method was generated for supporting the associations. */ protected void _initLinks() { } /** * This method was generated for supporting the associations. */ protected java.util.Vector _getLinks() { java.util.Vector links = new java.util.Vector(); return links; } /** * This method was generated for supporting the associations. */ protected void _removeLinks() throws java.rmi.RemoteException, javax.ejb.RemoveException { java.util.List links = _getLinks(); for (int i = 0; i < links.size() ; i++) { try { ((com.ibm.ivj.ejb.associations.interfaces.Link) links.get(i)).remove(); } catch (javax.ejb.FinderException e) {} //Consume Finder error since I am going away } } /** * Get accessor for persistent attribute: name */ public java.lang.String getName() { return name; } /** * Set accessor for persistent attribute: name */ public void setName(java.lang.String newName) { name = newName; } /** * Get accessor for persistent attribute: director */ public java.lang.String getDirector() { return director; } /** * Set accessor for persistent attribute: director */ public void setDirector(java.lang.String newDirector) { director = newDirector; } /** * ejbCreate * @param id String * @param name String * @param director String * @return TDepartmentKey */ public TDepartmentKey ejbCreate(String id,String name,String director) throws CreateException { this.id=id; setName(name); setDirector(director); return null; } /** * ejbPostCreate * @param id String * @param name String * @param director String * @return TDepartmentKey */ public void ejbPostCreate(String id,String name,String director) { } /** * generic Attribute method * @param Attri hashMap * */ public void changeValue(HashMap attri) { if(attri.containsKey("name")) { setName((String)attri.get("name")); } if(attri.containsKey("director")) { setDirector((String)attri.get("director")); } } } c、 TDepartment import java.rmi.RemoteException; import java.util.HashMap; import javax.ejb.EJBObject; /** * Remote interface for Enterprise Bean: TDepartment */ public interface TDepartment extends javax.ejb.EJBObject { /** * generic Attribute method * @param Attri hashMap * */ public void changeValue(HashMap attri) throws java.rmi.RemoteException; } ejb/rdb mapping(既是将数据项映射到映射数据库上), 生成map以后,可以查阅如下图 在ejb editor中,finder中,填写sql语句,一般来说可以选取Full select,或 whereclause,两者可用标准的sql表示,对于ejbql来说,适合ejb2.0 server层 用sessionbean封装usercase,每个method就是一个usercase 注意sessionbean中的所有方法,应只属于一个角色 进入j2ee perspective,过程与建立bmp一样,建立一个sessionbean package的命名如下: com.aostar.模块名称.server 其代码如下: 1、 TserverHome /** * Home interface for Enterprise Bean: Tserver */ public interface TserverHome extends javax.ejb.EJBHome { /** * Creates a default instance of Session Bean: Tserver */ public Tserver create() throws javax.ejb.CreateException, java.rmi.RemoteException; } 2、 Tserver import java.rmi.RemoteException; import javax.ejb.EJBObject; import javax.sql.RowSet; /** * Remote interface for Enterprise Bean: Tserver */ public interface Tserver extends javax.ejb.EJBObject { /** * * jdbc for reading * readData * @param birth1 String * @param birth2 String */ public RowSet readData(String birth1,String birth2) throws java.rmi.RemoteException; /** * * create * @param id String * @param name String * @param birth String * @param sex char */ public void create(String id,String name ,String birth,String sex) throws Exception, java.rmi.RemoteException; } 3、 TserverBean import java.sql.Connection; import java.sql.PreparedStatement; import java.util.HashMap; import javax.ejb.CreateException; import javax.ejb.FinderException; import javax.ejb.SessionBean; import javax.ejb.SessionContext; import javax.naming.Context; import javax.naming.InitialContext; import javax.sql.RowSet; import sun.jdbc.rowset.CachedRowSet; import com.aostor.persistence.Database; /** * Bean implementation class for Enterprise Bean: Tserver */ public class TserverBean implements javax.ejb.SessionBean { private javax.ejb.SessionContext mySessionCtx; /** * getSessionContext */ public javax.ejb.SessionContext getSessionContext() { return mySessionCtx; } /** * setSessionContext */ public void setSessionContext(javax.ejb.SessionContext ctx) { mySessionCtx = ctx; } /** * ejbActivate */ public void ejbActivate() { } /** * ejbCreate */ public void ejbCreate() throws javax.ejb.CreateException { } /** * ejbPassivate */ public void ejbPassivate() { } /** * ejbRemove */ public void ejbRemove() { } /** l getTDomainHome() l 取得domain层的home接口 */ public TDomainHome getTDomainHome() throws Exception { Context cxt=null; Try { cxt=new InitialContext(); return (TDomainHome)cxt.lookup("ejb/TDomain"); }catch(Exception ex) { ex.printStackTrace(); throw new Exception("the class of Tserver :"+ex.toString()); } finally { if(cxt!=null) { try { cxt.close(); } catch(Exception ex) { } cxt=null; } } } /** * 封装了Tdomain的修改和创建 * create * @param id String * @param name String * @param birth String * @param sex char */ public void create(String id,String name ,String birth,String sex) throws Exception { TDomainHome home=null; Try { //update,数据传输采用了HashMap模式 home=getTDomainHome(); TDomain domain=home.findByPrimaryKey(new TDomainKey(id)); HashMap attri=new HashMap(); attri.put("name",name); attri.put("birth",birth); attri.put("sex",sex); domain.changeValue(attri); }catch(FinderException fex) { //create try { home.create(id,name,birth,sex.charAt(0)); } catch(Exception ex) { ex.printStackTrace(); throw new Exception("the class of Tserver:"+ex.toString()); } }catch(Exception ex) { ex.printStackTrace(); throw new Exception("the class of Tserver:"+ex.toString()); } } /** l 查看多项数据 l 这里采用了jdbc for reading模式,数据传输采用了Rowset模式 * jdbc for reading * readData * @param birth1 String * @param birth2 String */ public RowSet readData(String birth1,String birth2) { Connection con=null; PreparedStatement pstt=null; Try { //connection con=Database.getConnection(); pstt=con.prepareStatement("select * from template1 where birth>=? and birth<=? "); pstt.setString(1,birth1); pstt.setString(2,birth2); CachedRowSet rs=new CachedRowSet(); rs.populate(pstt.executeQuery()); rs.setTableName("template1"); return rs; } catch(Exception ex) { ex.printStackTrace(); return null; } finally { if(pstt!=null) { try { pstt.close(); } catch(Exception ex) { } pstt=null; } if(con!=null) { try { con.close(); } catch(Exception ex) { } con=null; } } } /** * * jdbc for reading * readData * @param birth1 String * @param birth2 String */ public RowSet readDatatest(String birth1,String birth2) { DataAccessBean dab=new DataAccessBean(); Try { dab.setSql("select * from template1 where birth>=? and birth<=? "); dab.setString(1,birth1); dab.setString(2,birth2); CachedRowSet rs=new CachedRowSet(); rs.populate(dab.executeQuery()); rs.setTableName("template1"); return rs; } catch(Exception ex) { ex.printStackTrace(); return null; } finally { if(dab!=null) { try { dab.close(); } catch(Exception ex) { } dab=null; } } } } 注意:由于远端调用,要穿越防火墙,所以数据传输非常重要,可能会影响了整个系统性能,一般采用以下几个模式: hashmap模式:用HashMap来传递,见上面代码 DTO对象:DTO为数据传输对象,是序列化的,可在层与层之间的远端调用中传递,一般用于多行数据传递,可用于页面控制,需自己按需编写。 RowSet:多项数据传输,见上面代码 XML:多项数据传输,可用于页面控制 部署如domain层,调试如domain层 application 层] 作用:隔离ejb与jsp或者客户端程序,提供参数检验功能 businessdelegate 隔离表现层和server层,提供与server相同的方法,可增加数据类型检测了,一些论证 此处使用的时businessdelegate模型,一种在j2ee设计中最常用的模式,类似于模式设计中proxy模式 在java perspective中建立一个package,在其web项目的source目录下 com.aostar.模块名称.businessdelegate 建立一个class,Tbusiness 代码如下: package com.aostar.delegate; import javax.naming.Context; import javax.naming.InitialContext; import javax.sql.RowSet; import Tserver; import TserverHome; public class Tbuseness { /** l getTDomainHome() l 得到远端 l 如果存在大量的访问时,需要做一个专门的HomeFactory,用于控制和管理各个sessionBean的Home接口,并且它统一管理Home接口,并将businessdelegate和jininame隔离,因为jininame本身变动较大,这样HomeFactory很大程度的减少了代码修改,增加了代码的可复用性,代码如下 */ public Tserver getTserver() throws Exception { try { HomeFactory factory=HomeFactory.builder(); TserverHome home=(TserverHome)factory.findBy(TserverHome.class); return home.create(); } catch(Exception ex) { ex.printStackTrace(); throw ex; } } /** * update and create * @param id String * @param name String * @param birth String * @param sex String */ public void updateAndCreate(String id,String name ,String birth,String sex) throws Exception { //check data if(sex.length()!=1 && birth.length()!=8) { throw new Exception("error data formation"); } //execute try { Tserver delegate=getTserver(); delegate.create(id,name,birth,sex); } catch(Exception ex) { ex.printStackTrace(); throw new Exception("System error"); } } /** * showData * @param birth1 String * @param birth2 String * @return RowSet */ public RowSet showData(String birth1,String birth2) throws Exception { //check data if(birth1.length()!=8 && birth2.length()!=8) { throw new Exception("error data formation"); } //execute RowSet re=null; Try { Tserver delegate=getTserver(); if((re=delegate.readData(birth1,birth2))==null) { throw new Exception("returnvalue is null"); } } catch(Exception ex) { ex.printStackTrace(); throw new Exception("System error"); } return re; } } 在编译之前,需要导入所需ejb的包(包括Home,远端接口类,和一些成生的客户端调用class,考虑到储存空间现今已不是问题,可整个的打包),如图 在web perspective中,左键,出现下拉以后,点击properties进入相应界面 当然还有一种方式,就是在java build path 中project加入ejb项目既可,这是常用方法 备注:在项目中需要加入其他外面的包,比如说其他厂商开发的,如例子中引用了sun公司的RowSet包,方法于前一种类似,需要加入变量,但如果是ejb项目加包还需要包存放在运行目录中com.ibm.etools.websphere.runtime HomeFactory 用于大型的项目,采用了singleton model 和 flightweight model相应的原因如上述 代码如下: package com.aostar.home; import java.util.HashMap; import java.util.List; import java.util.Arrays; import javax.naming.Context; import javax.naming.InitialContext; import javax.rmi.PortableRemoteObject; import TserverHome; import com.aostar.exception.HomeFactoryCreateException; public class HomeFactory { //singleton model static HomeFactory factory=null; //flightweight model static HashMap map=null; final static String[] jdbcName={"ejb/Tserver"}; final static Class[] classes={TserverHome.class}; final static int COUNT=1; /** * constructor */ private HomeFactory() throws HomeFactoryCreateException { map=new HashMap(); Context ctx=null; Try { ctx=new InitialContext(); List jdbcList=Arrays.asList(jdbcName); for(int i=0;i test.jsp

it is a test

<% CachedRowSet rs=(CachedRowSet)business.showData("20000101","20031011"); %> <% while(rs.next()){ %> <%}%>
idnamebirth yearsex
<%=rs.getString("id")%><%=rs.getString("name")%><%=rs.getString("birth")%><%=rs.getString("sex")%>
其他需要注意的 事务:entity bean是container管理,sessionbean,可选(container和application管理),container管理事务,分为六种事务 在wsad中配置事务如图:j2ee perspective中,选定ejb editor,如图 然后添加事务 <淘宝热门商品:
 

78.00 元 

印疤修复液 消除深浅痘印 改善凹凸疤痕

 

108.00 元  

电视购物热销.夏娃之秀魔力挺,让女人都有杀人"胸"器


来源:程序员网

小小豆叮

Java开发中的线程安全选择与Swing

Swing API的设计目标是强大、灵活和易用。特别地,我们希望能让程序员们方便地建立新的Swing组件,不论是从头开始还是通过扩展我们所提供的一些组件。   出于这个目的,我们不要求Swing组件支持多线程访问。相反,我们向组件发送请求并在单一线程中执行请求。   本文讨论线程和Swing组件。目的不仅是为了帮助你以线程安全的方式使用Swing API,而且解释了我们为什么会选择现在这样的线程方案。   本文包括以下内容:    单线程规则:Swing线程在同一时刻仅能被一个线程所访问。一般来说,这个线程是事件派发线程(event-dispatching thread)。    规则的例外:有些操作保证是线程安全的。    事件分发:如果你需要从事件处理(event-handling)或绘制代码以外的地方访问UI,那么你可以使用SwingUtilities类的invokeLater()或invokeAndWait()方法。    创建线程:如果你需要创建一个线程——比如用来处理一些耗费大量计算能力或受I/O能力限制的工作——你可以使用一个线程工具类如SwingWorker或Timer。    为什么我们这样实现Swing:我们将用一些关于Swing的线程安全的背景资料来结束这篇文章。   Swing的规则是:   一旦Swing组件被具现化(realized),所有可能影响或依赖于组件状态的代码都应该在事件派发线程中执行。   这个规则可能听起来有点吓人,但对许多简单的程序来说,你用不着为线程问题操心。在我们深入如何撰写Swing代码之前,让我们先来定义两个术语:具现化(realized)和事件派发线程(event-dispatching thread)。   具现化的意思是组建的paint()方法已经或可能会被调用。一个作为顶级窗口的Swing组件当调用以下方法时将被具现化:setVisible(true)、show()或(可能令你惊奇)pack()。当一个窗口被具现化,它包含的所有组件都被具现化。另一个具现化一个组件的方法是将它放入到一个已经具现化的容器中。稍后你会看到一些对组件具现化的例子。   事件派发线程是执行绘制和事件处理的线程。例如,paint()和actionPerformed()方法会自动在事件派发线程中执行。另一个将代码放到事件派发线程中执行的方法是使用SwingUtilities类的invokeLater()方法。   所有可能影响一个已具现化的Swing组件的代码都必须在事件派发线程中执行。但这个规则有一些例外:   有些方法是线程安全的:在Swing API的文档中,线程安全的方法用以下文字标记:   This method is thread safe, although most Swing methods are not.   (这个方法是线程安全的,尽管大多数Swing方法都不是。) 一个应用程序的GUI常常可以在主线程中构建和显示:下面的典型代码是安全的,只要没有(Swing或其他)组件被具现化: public class MyApplication {  public static void main(String[] args)  {   JFrame f = new JFrame("Labels"); // 在这里将各组件    // 加入到主框架……    f.pack();    f.show();    // 不要再做任何GUI工作……   } }   上面所示的代码全部在“main”线程中运行。对f.pack()的调用使得JFrame以下的组件都被具现化。这意味着,f.show()调用是不安全的且应该在事件派发线程中执行。尽管如此,只要程序还没有一个看得到的GUI,JFrame或它的里面的组件就几乎不可能在f.show()返回前收到一个paint()调用。因为在f.show()调用之后不再有任何GUI代码,于是所有GUI工作都从主线程转到了事件派发线程,因此前面所讨论的代码实际上是线程安全的。   一个applet的GUI可以在init()方法中构造和显示:现有的浏览器都不会在一个applet的init()和start()方法被调用前绘制它。因而,在一个applet的init()方法中构造GUI是安全的,只要你不对applet中的对象调用show()或setVisible(true)方法。   要顺便一提的是,如果applet中使用了Swing组件,就必须实现为JApplet的子类。并且,组件应该添加到的JApplet内容窗格(content pane)中,而不要直接添加到JApplet。对任何applet,你都不应该在init()或start()方法中执行费时的初始化操作;而应该启动一个线程来执行费时的任务。   下述JComponent方法是安全的,可以从任何线程调用:repaint()、revalidate()、和invalidate()。repaint()和revalidate()方法为事件派发线程对请求排队,并分别调用paint()和validate()方法。invalidate()方法只在需要确认时标记一个组件和它的所有直接祖先。   监听者列表可以由任何线程修改:调用addListenerTypeListener()和removeListenerTypeListener()方法总是安全的。对监听者列表的添加/删除操作不会对进行中的事件派发有任何影响。   注意:revalidate()和旧的validate()方法之间的重要区别是,revalidate()会缓存请求并组合成一次validate()调用。这和repaint()缓存并组合绘制请求类似。   大多数初始化后的GUI工作自然地发生在事件派发线程。一旦GUI成为可见,大多数程序都是由事件驱动的,如按钮动作或鼠标点击,这些总是在事件派发线程中处理的。   不过,总有些程序需要在GUI成为可见后执行一些非事件驱动的GUI工作。比如:   在成为可用前需要进行长时间初始化操作的程序:这类程序通常应该在初始化期间就显示出GUI,然后更新或改变GUI。初始化过程不应该在事件派发线程中进行;否则,重绘组件和事件派发会停止。尽管如此,在初始化之后,GUI的更新/改变还是应该在事件派发线程中进行,理由是线程安全。   必须响应非AWT事件来更新GUI的程序:例如,想象一个服务器程序从可能运行在其他机器上的程序得到请求。这些请求可能在任何时刻到达,并且会引起在一些可能未知的线程中对服务器的方法调用。这个方法调用怎样更新GUI呢?在事件派发线程中执行GUI更新代码。   SwingUtilities类提供了两个方法来帮助你在事件派发线程中执行代码:    invokeLater():要求在事件派发线程中执行某些代码。这个方法会立即返回,不会等待代码执行完毕。    invokeAndWait():行为与invokeLater()类似,除了这个方法会等待代码执行完毕。一般地,你可以用invokeLater()来代替这个方法。   下面是一些使用这几个API的例子。请同时参阅《The Java Tutorial》中的“BINGO example”,尤其是以下几个类:CardWindow、ControlPane、Player和OverallStatusPane。 使用invokeLater()方法   你可以从任何线程调用invokeLater()方法以请求事件派发线程运行特定代码。你必须把要运行的代码放到一个Runnable对象的run()方法中,并将此Runnable对象设为invokeLater()的参数。invokeLater()方法会立即返回,不等待事件派发线程执行指定代码。这是一个使用invokeLater()方法的例子: Runnable doWorkRunnable = new Runnable() {  public void run()  {   doWork();   } }; SwingUtilities.invokeLater(doWorkRunnable);   使用invokeAndWait()方法   invokeAndWait()方法和invokeLater()方法很相似,除了invokeAndWait()方法会等事件派发线程执行了指定代码才返回。在可能的情况下,你应该尽量用invokeLater()来代替invokeAndWait()。如果你真的要使用invokeAndWait(),请确保调用invokeAndWait()的线程不会在调用期间持有任何其他线程可能需要的锁。 这是一个使用invokeAndWait()的例子: void showHelloThereDialog() throws Exception {  Runnable showModalDialog = new Runnable()  {   public void run()   {    JOptionPane.showMessageDialog( myMainFrame, "Hello There");    }   };  SwingUtilities.invokeAndWait (showModalDialog); }   类似地,假设一个线程需要对GUI的状态进行存取,比如文本域的内容,它的代码可能类似这样: void printTextField()   throws Exception {    final String[] myStrings = new String[2];    Runnable getTextFieldText = new Runnable() {     public void run() {      myStrings[0] = textField0.getText();      myStrings[1] = textField1.getText();     }    };    SwingUtilities.invokeAndWait (getTextFieldText);    System.out.println(myStrings[0] + " " + myStrings[1]);}   如果你能避免使用线程,最好这样做。线程可能难于使用,并使得程序的debug更困难。一般来说,对于严格意义下的GUI工作,线程是不必要的,比如对组件属性的更新。   不管怎么说,有时候线程是必要的。下列情况是使用线程的一些典型情况:   执行一项费时的任务而不必将事件派发线程锁定。例子包括执行大量计算的情况,会导致大量类被装载的情况(如初始化),和为网络或磁盘I/O而阻塞的情况。   重复地执行一项操作,通常在两次操作间间隔一个预定的时间周期。   要等待来自客户的消息。   你可以使用两个类来帮助你实现线程:    SwingWorker:创建一个后台线程来执行费时的操作。    Timer:创建一个线程来执行或多次执行某些代码,在两次执行间间隔用户定义的延迟。 使用SwingWorker类   SwingWorker类在SwingWorker.java中实现,这个类并不包含在Java的任何发行版中,所以你必须单独下载它。   SwingWorker类做了所有实现一个后台线程所需的肮脏工作。虽然许多程序都不需要后台线程,后台线程在执行费时的操作时仍然是很有用的,它能提高程序的性能观感。 SwingWorker's get() method. Here's an example of using SwingWorker:   要使用SwingWorker类,你首先要实现它的一个子类。在子类中,你必须实现construct()方法还包含你的长时间操作。当你实例化SwingWorker的子类时,SwingWorker创建一个线程但并不启动它。你要调用你的SwingWorker对象的start()方法来启动线程,然后start()方法会调用你的construct()方法。当你需要construct()方法返回的对象时,可以调用SwingWorker类的get()方法。这是一个使用SwingWorker类的例子: ...// 在main方法中: final SwingWorker worker = new SwingWorker() {  public Object construct() {   return new expensiveDialogComponent();   } }; worker.start(); ... // 在动作事件处理方法中: JOptionPane.showMessageDialog (f, worker.get());   当程序的main()方法调用start()方法,SwingWorker启动一个新的线程来实例化ExpensiveDialogComponent。main()方法还构造了由一个窗口和一个按钮组成的GUI。   当用户点击按钮,程序将阻塞,如果必要,阻塞到ExpensiveDialogComponent创建完成。然后程序显示一个包含ExpensiveDialogComponent的模式对话框。你可以在MyApplication.java找到整个程序。   使用Timer类   Timer类通过一个ActionListener来执行或多次执行一项操作。你创建定时器的时候可以指定操作执行的频率,并且你可以指定定时器的动作事件的监听者(action listener)。启动定时器后,动作监听者的actionPerformed()方法会被(多次)调用来执行操作。   定时器动作监听者(action listener)定义的actionPerformed()方法将在事件派发线程中调用。这意味着你不必在其中使用invokeLater()方法。   这是一个使用Timer类来实现动画循环的例子: public class AnimatorApplicationTimer  extends JFrame implements ActionListener {   ...//在这里定义实例变量   Timer timer;   public AnimatorApplicationTimer(...) {    ... // 创建一个定时器来    // 来调用此对象action handler。    timer = new Timer(delay, this);    timer.setInitialDelay(0);    timer.setCoalesce(true);    ...   }   public void startAnimation() {    if (frozen) {     // 什么都不做。应用户要求     // 停止变换图像。    } else {     // 启动(或重启动)动画!     timer.start();    }   }   public void stopAnimation() {    // 停止动画线程。    timer.stop();   }   public void actionPerformed (ActionEvent e)   {    // 进到下一帧动画。    frameNumber++;    // 显示。    repaint();   }   ... } 在一个线程中执行所有的用户界面代码有这样一些优点:   组件开发者不必对线程编程有深入的理解:像ViewPoint和Trestle这类工具包中的所有组件都必须完全支持多线程访问,使得扩展非常困难,尤其对不精通线程编程的开发者来说。最近的一些工具包如SubArctic和IFC,都采用和Swing类似的设计。   事件以可预知的次序派发:invokeLater()排队的runnable对象从鼠标和键盘事件、定时器事件、绘制请求的同一个队列派发。在一些组件完全支持多线程访问的工具包中,组件的改变被变化无常的线程调度程序穿插到事件处理过程中。这使得全面测试变得困难甚至不可能。   更低的代价:尝试小心锁住临界区的工具包要花费实足的时间和空间在锁的管理上。每当工具包中调用某个可能在客户代码中实现的方法时(如public类中的任何public和protected方法),工具包都要保存它的状态并释放所有锁,以便客户代码能在必要时获得锁。当控制权交回到工具包,工具包又必须重新抓住它的锁并恢复状态。所有应用程序都不得不负担这一代价,即使大多数应用程序并不需要对GUI的并发访问。   这是的SubArctic Java Toolkit的作者对在工具包中支持多线程访问的问题的描述:   我们的基本信条是,当设计和建造多线程应用程序,尤其是那些包括GUI组件的应用程序时,必须保证极端小心。线程的使用可能会很有欺骗性。在许多情况下,它们表现得能够极好的简化编成,使得设计“专注于单一任务的简单自治实体”成为可能。在一些情况下它们的确简化了设计和编码。然而,在几乎所有的情况下,它们都使得调试、测试和维护的困难大大增加甚至成为不可能。无论大多数程序员所受的训练、他们的经验和实践,还是我们用来帮助自己的工具,都不是能够用来对付非决定论的。例如,全面测试(这总是困难的)在bug依赖于时间时是几乎不可能的。尤其对于Java来说,一个程序要运行在许多不同类型的机器的操作系统平台上,并且每个程序都必须在抢先和非抢先式调度下都能正常工作。   由于这些固有的困难,我们力劝你三思是否绝对有使用线程的必要。尽管如此,有些情况下使用线程是必要的(或者是被其他软件包强加的),所以subArctic提供了一个线程安全的访问机制。本章讨论了这一机制和怎样在一个独立线程中安全地操作交互树。   他们所说的线程安全机制非常类似于SwingUtilities类提供的invokeLater()和invokeAndWait()方法。 <淘宝热门商品:
 

68.00 元 

超人气神奇魔水 柔嫩细滑肌肤一喷即成

 

128.00 元  

【广州商盟】*大学生淘宝皇冠第一店-鞋神--三人行出口剩余旗舰店

【大学生皇冠店】new balance纽巴伦378经典款 天蓝


来源:程序员网

小小豆叮

用Java动态代理来创建包装器

Java 1.3引入了名为“动态代理类”(Dynamic Proxy Class)的新特性,利用它可为“已知接口的实现”动态地创建包装器(wrapper)类。1.3版本问世以前,当我首次听说当时正在提议的动态代理类时,还以为它只是一种用来吸引人的眼球的特性。虽然把它包括到语言中是一件好事,但我却想不出它有任何实际用处。带着这一成见,我试着用动态代理写了一个示例程序,却惊讶于它的巨大威力,并当即决定把它放到我的工具箱中,以便在将来的项目中使用。此后,我不断体验到它的好处,它总是能用正确的方法来做你想要做的事情! 假如没有动态代理 深入探索动态代理类之前,先来看看在某些情况下,假如没有动态代理类会是什么样子: public interface Robot { void moveTo(int x, int y); void workOn(Project p, Tool t); } public class MyRobot implements Robot { public void moveTo(int x, int y) { // stuff happens here } public void workOn(Project p, Tool t) { // optionally destructive stuff happens here } } 上述代码展示了一个名为Robot的接口,以及该接口的一个名为MyRobot的大致的实现。假定你现在想拦截对MyRobot类发出的方法调用(可能是为了限制一个参数的值)。 public class BuilderRobot implements Robot { private Robot wrapped; public BuilderRobot(Robot r) { wrapped = r; } public void moveTo(int x, int y) { wrapped.moveTo(x, y); } public void workOn(Project p, Tool t) { if (t.isDestructive()) { t = Tool.RATCHET; } wrapped.workOn(p, t); } } 一个办法就是使用显式的包装器类,就像上面显示的那样。BuilderRobot类在其构造函数中获取一个Robot,并拦截workOn方法,确保在任何项目中使用的工具都没有破坏性。另外,由于BuilderRobot这一包装器实现了Robot接口,所以凡是能够使用一个Robot的任何地方,都能使用一个BuilderRobot实例。 对于这种包装器风格的BuilderRobot来说,一旦你想修改或扩展Robot接口,它的缺点就会暴露无遗。为Robot接口添加一个方法,就得为BuilderRobot类添加一个包装器方法。为Robot添加10个方法,就得为BuilderRobot添加10个方法。如果BuilderRobot、CrusherRobot、SpeedyRobot和SlowRobot都是Robot包装器类,就必须分别为它们添加10个方法。这显然是效率极差的一种方案。 public class BuilderRobot extends MyRobot { public void workOn(Project p, Tool t) { if (t.isDestructive()) { t = Tool.RATCHET; } super.workOn(p, t); } } 上述代码是对 BuilderRobot进行编程的另一种方式。注意BuilderRobot变成了MyRobot的一个子类。这样可解决在第2段代码的包装器方案中出现的问题。也就是说,修改Robot接口不必修改BuilderRobot。但这又产生了一个新问题:只有MyRobot对象才能是BuilderRobot。而在此之前,实现了Robot接口的任何对象都可以成为一个BuilderRobot。现在,由Java施加的“线性类出身限制”(linear class parentage restrictions)禁止我们将任意Robot(ArbitraryRobot)变成一个BuilderRobot。 动态代理也有限制 动态代理则综合了以上两种方案的优点。使用动态代理,你创建的包装器类不要求为所有方法都使用显式的包装器,创建的子类也不要求具有严格的出身,两者方法可任选一种你认为最好的。但是,动态代理仍然有一个限制。当你使用动态代理时,要包装/扩展的对象必须实现一个接口,该接口定义了准备在包装器中使用的所有方法。这一限制的宗旨是鼓励良好的设计,而不是为你带来更多的麻烦。根据经验,每个类都至少应该实现一个接口(nonconstant接口)。良好的接口用法不仅使动态代理成为可能,还有利于程序的模块化。 使用动态代理 下面的代码演示了用动态代理来创建一个BuilderRobot时所必需的类。注意我们创建的这个BuilderRobotInvocationHandler类甚至根本没有实现Robot接口。相反,它实现了java.lang.reflect.InvocationHandler,只提供了一个invoke方法。代理对象上的任何方法调用都要通过这一方法进行。观察invoke的主体,我们发现它会检查准备调用的方法的名称。如果这个名称是workOn,第二个参数就切换成一个非破坏性的工具。 然而,我们得到的仍然只是一个具有invoke方法的InvocationHandler,而不是我们真正想要的Robot对象。动态代理真正的魅力要到创建实际的Robot实例时才能反映出来。在源代码的任何地方,我们都没有定义一个Robot包装器或者子类。虽然如此,我们最终仍能获得一个动态创建的类,它通过调用BuilderRobotInvocationHandler的静态方法createBuilderRobot中的代码片断,从而实现了Robot接口,并集成了Builder工具过滤器。 import java.lang.reflect.Proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class BuilderRobotInvocationHandler implements InvocationHandler { private Robot wrapped; public BuilderRobotInvocationHandler(Robot r) { wrapped = r; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ("workOn".equals(method.getName())) { args[1] = Tool.RATCHET; } return method.invoke(wrapped, args); } public static Robot createBuilderRobot(Robot toWrap) { return (Robot)(Proxy.newProxyInstance(Robot.class.getClassLoader(), new Class[] {Robot.class}, new BuilderRobotInvocationHandler(toWrap))); } public static final void main(String[] args) { Robot r = createBuilderRobot(new MyRobot()); r.workOn("scrap", Tool.CUTTING_TORCH); } } createBuilderRobot中的代码表面上很复杂,但它的作用其实很简单,就是告诉Proxy类用一个指定的类加载器来动态创建一个对象,该对象要实现指定的接口(本例为Robot),并用提供的InvocationHandler来代替传统的方法主体。结果对象在一个instanceof Robot测试中返回true,并提供了在实现了Robot接口的任何类中都能找到的方法。 有趣的是,在BuilderRobotInvocationHandler类的invoke方法中,完全不存在对Robot接口的引用。InvocationHandlers并不是它们向其提供了“代理方法实现”的接口所专用的,你完全可以写一个InvocationHandler,并将其作为众多代理类的后端来使用。 但在本例中,我们以构造函数参数的形式,为BuilderRobotInvocationHandler提供了RobotInterface的另一个实例。代理Robot实例上的任何方法调用最终都由BuilderRobotInvocationHandler委托给这个“包装的”Robot。但是,虽然这是最常见的设计,但你必须了解,InvocationHandler不一定非要委托给被代理的接口的另一个实例。事实上,InvocationHandler完全能自行提供方法主体,而无需一个委托目标。 最后要注意,如果Robot接口中发生改变,那么BuilderRobotInvocationHandler中的invoke方法将反应迟钝。例如,假定workOn方法被重命名,那么非破坏性工具陷阱会悄悄地失败,这时的BuilderRobots就有可能造成损害。较容易检测、但却不一定会造成问题的是workOn方法的重载版本。如果方法具有相同的名称,但使用一个不同的参数列表,就可能在运行时造成一个ClassCastException或者ArrayIndexOutOfBoundsException异常。为此,以下代码给出了一个解决方案,它能生成一个更灵活的BuilderRobotInvocationHandler。在这段代码中,任何时候在任何方法中使用一个工具,这个工具就会被替换成一个非破坏性工具。请试着用子类化处理或者传统的委托来进行试验。 import java.lang.reflect.Proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class BuilderRobotInvocationHandler implements InvocationHandler { private Robot wrapped; public BuilderRobotInvocationHandler(Robot r) { wrapped = r; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Class[] paramTypes = method.getParameterTypes(); for (int i=0; i < paramTypes.length; i++) { if (Tool.class.isAssignableFrom(paramTypes[i])) { args[i] = Tool.RATCHET; } } return method.invoke(wrapped, args); } public static Robot createBuilderRobot(Robot toWrap) { return (Robot)(Proxy.newProxyInstance(Robot.class.getClassLoader(), new Class[] {Robot.class}, new BuilderRobotInvocationHandler(toWrap))); } public static final void main(String[] args) { Robot r = createBuilderRobot(new MyRobot()); r.workOn("scrap", Tool.CUTTING_TORCH); } } 使用建议 在大多数开发环境中,用工具来取代Robot并不是一种常见的操作。还有其他许多方式可以使用动态代理。它们提供了一个调试层,可方便地记录一个对象上的所有方法调用的具体细节。它们可执行绑定检查,并对方法参数进行验证。在与远程数据源发生冲突的前提下,甚至可用它们将备用的本地测试后端动态地交换出去。如果你采用的是良好的、由接口驱动的设计方案,我个人觉得动态代理的用处肯定要比你想象的多,最终你会叹服于它从容解决许多问题的本事! <淘宝热门商品:
 

 

【珠三角商盟】【因为专注→所以专业→天天数码世界】

 

 

专做VIVI昕薇瑞丽韩日女装~


来源:程序员网

小小豆叮

关于JAVA的字符编码问题

关于字符编码的概念及技巧 在基于 Java 语言的编程中,我们经常碰到汉字的处理及显示的问题。 Java 语言默认的编码方式是UNICODE ,它给JAVA带来了活力,及更广的适应性,但是问题也随之而来 我们通常使用的文件和数据库一般都是基于 GB2312 或者 BIG5 等方式编码的,怎样才能够恰当地选择汉字编码方式并正确地处理汉字的编码呢? 英文字符一般是以一个字节来表示的,最常用的编码方法是 ASCII 。但一个字节最多只能区分 256个字符,而汉字成千上万,所以现在都以双字节来表示汉字,为了能够与英文字符分开, 每个字节的最高位一定为1,这样双字节最多可以表示64K格字符。我们经常碰到的编码方式有 GB2312、BIG5、UNICODE 等。关于具体编码方式的详细资料,有兴趣的读者可以查阅相关资料。 GB2312是国标码。两个字节中,第一个字节(高字节)的值为区号值加32(20H),第二个字节(低字节) 的值为位号值加32(20H),用这两个值来表示一个汉字的编码。 UNICODE 码是微软提出的解决多国字符问题的多字节等长编码,它对英文字符采取前面加“0”字节的策略 实现等长兼容。如 “A” 的 ASCII 码为0x41,UNICODE 就为0x00,0x41,利用特殊的工具各种编码之间可以 互相转换。 我们经常碰到这样的情况:浏览基于 JSP 技术的网站看到的是乱码,文件打开后看到的也是乱码, 这是因为 外部文件-> Java 字节码-> ;虚拟机->操作系统->显示设备” 这个转变过程有了问题。 首先看一个JSP中的解决中文问题的例子,我想这段代码大家都很熟悉吧, 但他的具体含义是什么呢?为什么要这样做呢? String s1 = request.getParameter(“keyword”); //从request中取参数 s1 byte[] bytes=s1.getBytes(“ISO-8859-1”); //把s1(按Unicode->ISO-8859-1) 转回原来的byte[]。 String s2 = new String(bytes,”GBK”); //因为原来的参数(或字符,字串)是GBK编码方式,所以把bytes //按照GBK->Unicode的方式转码 为什么要这样做呢?因为接收的参数本来是GBK编码方式的,但是缺省的用了 iso-8859-1->Unicode 的转码方式把参数转成了String 所以肯定是乱码(中文时) 只要了解了这个基本道理,中文字符问题应该都能解决! <淘宝热门商品:
 

18.00 元 

最新版 2面圆领打底衫 精品莱卡棉

 

 

【25元或以上商品任意2件包运】【时尚卓尔】-个性随我秀


来源:程序员网

小小豆叮

jdbc 连接常见的数据库

jdbc 连接几种常见的数据库 常见的数据库的连接方法: 具体的jdbc API 的用法我就省略了。 oracle drive: oracle.jdbc.driver.OracleDriver connect String: "jdbc:oracle:thin:@hostip:1521:oracleSID" sybase: drive: com.sybase.jdbc.SybDriver connect String: "jdbc:sybase:Tds:hostip:4000/databasename" DB2: drive: COM.ibm.db2.jdbc.app.DB2Driver connect String: "jdbc:db2://hostip:8888/databasename" sqlserver: drive: com.microsoft.jdbc.sqlserver.SQLServerDriver connect String: "jdbc:microsoft:sqlserver://hostip:1433" <淘宝热门商品:
 

26.00 元  

时尚巴黎女人街 V 火爆这个冬季

附带女人我最大推荐魔法烘罩器电吹风机人性化冷暖风切换魔发冬夏

 

 

伊人红妆赛维芦荟胶相宜本草昭贵田缘舞沙千纤草大宝庆琇郁美净


来源:程序员网

小小豆叮

java开发的邮件发送程序

Java的网络功能非常强大,开发和使用也非常简单,难怪microsoft极力要争回程序语言的霸主地位。笔者根据smtp协议使用java Socket写了一个发送邮件的程序,将此与各位分享。 实现的原理非常简单,首先建立和邮件服务器的Socket连接,然后进行和服务器握手,然后发送smtp指令,并封装邮件体,然后发送即可。大家不妨一试。由什么问题可以和我联系:Email:linlichao@163.com;Homepage:http://www.ehawa.com。 import java.net.*; import java.io.*; import java.util.*; public class SMTPSender{ Socket socket=null; PrintWriter outData=null; BufferedReader inData=null; String smtpServer=""; String user=""; String pass=""; String from=""; String LINEFEED="\r\n"; boolean isNeedAuthLogin=false; Vector to=new Vector(); public static void main(String[] args){ SMTPSender smtp=new SMTPSender(); smtp.setMailServer("mail.ehawa.com"); smtp.setMailFrom("root@ehawa.com","???","???"); smtp.addMailTo("root@ehawa.com"); if(smtp.send("hello","这是一个测试!")){ System.out.println("邮件发送成功!"); }else System.out.println("邮件发送失败!"); } public void setMailServer(String s){ smtpServer=s; } public void setMailFrom(String s,String uid,String pwd){ this.from=s; this.user=uid; this.pass=pwd; this.isNeedAuthLogin=(this.user!=null&&this.pass!=null&&!this.user.equals("")&&!this.pass.equals("")); } public boolean addMailTo(String mailAddr){ to.addElement(mailAddr); return true; } public boolean send(String subject,String content){ try{ if(smtpServer==null||smtpServer.equals(""))return false; if(from==null||from.equals(""))return false; if(to.size()<1)return false; socket=new Socket(smtpServer,25); outData=new PrintWriter(socket.getOutputStream()); inData=new BufferedReader(new InputStreamReader(socket.getInputStream())); //与邮件服务器连接成功 readResponse("220"); //HELO host sendRequest("HELO "+smtpServer+LINEFEED); readResponse("250"); if(isNeedAuthLogin){ //AUTH LOGIN sendRequest("AUTH LOGIN"+LINEFEED); readResponse("334"); //USERNAME: sendRequest(new String(Base64.encodeString(user))+LINEFEED); readResponse("334"); //PASSWORD: sendRequest(new String(Base64.encodeString(pass))+LINEFEED); readResponse("235"); } //MAIL FROM:<..> sendRequest("MAIL FROM:<"+from+">"+LINEFEED); readResponse("250"); //RCPT TO:<..> for(Enumeration enu=to.elements();enu.hasMoreElements();){ String to1=(String)enu.nextElement(); sendRequest("RCPT To:<"+to1+">"+LINEFEED); readResponse("250"); } //DATA sendRequest("DATA"+LINEFEED); readResponse("354"); //邮件内容 StringBuffer s1=new StringBuffer("From: <"+from+">"+LINEFEED); s1.append("To: <"+to+">"+LINEFEED); s1.append("Subject: "+subject+LINEFEED); s1.append("Date: "+new java.util.Date().toLocaleString()+LINEFEED); s1.append("Content-Type: text/plain;charset=\"GB2312\""+LINEFEED); s1.append(LINEFEED); s1.append(content); s1.append(LINEFEED+"."+LINEFEED);//发送 sendRequest(s1.toString()); readResponse("250"); //QUIT退出 sendRequest("QUIT"+LINEFEED); readResponse("221"); try{ inData.close(); inData=null; }catch(Exception ex){} try{ outData.close(); outData=null; }catch(Exception ex){} try{ socket.close(); socket=null; }catch(Exception ex){} }catch(Exception e){ return false; //e.printStackTrace(); } return true; } private void readResponse(String cmd)throws Exception{ String tmp=inData.readLine(); if(tmp.startsWith(cmd));//System.out.println(" [S:]"+tmp); else throw new Exception("##########邮件发送失败!##########"+tmp); while(tmp.startsWith(cmd+"-"))tmp=inData.readLine(); } private void sendRequest(String msg){ //System.out.print("***[C:]"+msg); outData.write(msg); outData.flush(); } public void close(){ try{ inData.close(); inData=null; }catch(Exception ex){} try{ outData.close(); outData=null; }catch(Exception ex){} try{ socket.close(); socket=null; }catch(Exception ex){} } } <淘宝热门商品:
 

99.00 元  

皇冠联盟增高鞋垫 鞋(足)护理原单服装批发店

【韩国内增高魔力秀腿鞋】◆增高6公分◆惊爆价99元◆银粉

 

运动鞋 

地球都踩在脚下


来源:程序员网

小小豆叮

JAVA数据对象上机实践

Java 数据对象(Java Data Objects (JDO))是 Sun Microsystems 的一项新技术。尽管 JDO 还有些不成熟(刚发布 1.0 规范),但它很有发展前景,而且它填补了数据库编程领域的一大空白。对 Java 开发人员而言,JDO 为对象持久性提供了第一个标准化的、完全面向对象的方法。与此领域中的其它技术相比,JDO 的优点是使用起来十分简单,而且对原始的 Java 源代码的打乱程度最小。另外,即使对于经验丰富的程序员而言,JDBC 和 EJB 容器管理的持久性(EJB Container Managed Persistence (EJB CMP))也显得很复杂,而 JDO 在简化用 Java 语言进行数据库编程的某些最复杂方面做了许多工作。本教程中,我们将使用讨论、代码样本以及上机练习来了解有关 JDO 的实际应用。 预备知识   本教程是为中高级 Java 开发人员设计的。要最大程度地掌握本教程,您应该具有使用 Java 2 平台的经验,并对关系数据库的工作原理有很好的理解。了解一些 JDBC 知识也会很有用。我们把本教程特别推荐给那些寻求处理对象中持久性方法的开发人员。如果您不想使用“笨重”的 EJB 技术,又不想处理 JDBC 所带来的关系语义,那么 JDO 可以提供了满足您需要的两全其美的解决方案。 系统需求   JDO 可以与 Java 2 平台,标准版平台结合使用。从 Sun Microsystems 上下载的 JDO 的确带有参考实现,但编写本教程时,该参考实现还被认为是不可靠的。其工具不够健壮,还不能用于一般用途。在 LIBeLIS 上可以免费获得一个更可靠的 JDO 实现(用于教育目的,需注册)。本教程中的练习都基于 LIBeLIS JDO 实现。除了 JDO 实现外,您还需要 JDBC 驱动程序和关系数据库来完成练习。除了 JDO 实现外,练习使用的所有工具都是开放源码。需要下列技术和资源以完成本教程中的练习: LIBeLIS 社区版 JDO(LiDO)。下载时需进行站点注册。 Java 2 平台,标准版。 用于编译和运行示例的标准编辑器和 JDK。 MySQL 开放源码关系数据库。 用于 MySQL 的 MM.MySQL 开放源码 JDBC 驱动程序。 示例的二进制文件和源代码。   教程   『开始学习本教程:进入本教程』    <淘宝热门商品:
 

 

柠檬绿茶 淘宝第一(唯一)100万双金冠信誉! 网络白领女性超市!

 

35.00 元 

【天使名妆】100%纯棉休闲瑜珈裤


来源:程序员网

小小豆叮

找出不同版本代码之间的区别

有时,你想知道代码的两个版本之间有哪些变化。如果你很认真勤勉,每次都做变更记录或者在版本控制系统中做注释,那么你可以很容易发现这些不同点。但是,即使是最认真的开发人员偶尔也会忘记写文档。 JDiff就是这么一个工具:它用Javadoc的格式,向你报告的源代码的两个版本之间的区别。你可以对你想做对比的任何版本的代码使用JDiff。每个应用都创建一个XML文档描述源代码。然后,你再对这两个刚创建的XML文档使用JDiff。在这种情况下,JDiff会创建了一个HTML文件来显示两个版本的不同。 JDiff是作为一个文档制作工具(doclet)实现的,因此你用Javadoc工具来运行它。JDiff的输出看起来就像你平时习惯的,通过包、类、方法等等来显示变化的完整的列表的Javadoc一样。 当你需要看不同版本之间的区别,那么你可以用JDiff简化这个过程。 <淘宝热门商品:
 

 

[玉缘阁精品和田玉]和田美玉 送物传情 13779692122翡翠

 

78.00 元 

卖疯了 顶级瘦脸 顾客赞不停


来源:程序员网

小小豆叮

对《Java与模式》中工厂方法模式的异议

关于工厂方法的一点讨论,我们知道工厂方法属于类型创建模式,而抽象工厂属于对象创建模式,并且所谓的类创建模式就是把创建工作延迟到子类,而对象创建模式则将延迟到另一个对象。   并且设计模式中指出,类模式处理类和子类子间的关系,这些关系通过继承建立,是静态的,在编译时刻便确定下来。对象模式则处理对象之间的关系,是动态的,运行时刻是可以变化的,更具动态性。   工厂方法由于属于类型创建模式,因此它的创建工作由子类完成,而不是使用对象进行创建,并且在《设计模式》中工厂方法的动机一节有一个示例,它的类大致如下: //抽象产品,可以是接口或者抽象类 public abstract class document { public void open(){ ............... ............... } public void close(){ ............... ............... } public void save(); } //具体的产品, public class Mydocument extends document{ public void open(){ ............. .............. } ............... } 我们工厂方法 public abstract class appliaction { //该方法是工厂方法,由子类实现 public abstract document createDocument(); //模板方法,在方法中使用了工厂方法 pubic void newDocument(){ //使用工厂方法,获得doc,而实际有子类完成,//这里可以看出,对象的创建,是通过继承来实现,是静态的,编译时已经确定//而不是通过对象的委托来实现,故属于类创建型模式 Document doc=createDocument(); doc.open(); .................... doc.save(); } }   具体的工厂实现由子类来实现工厂方法: public class myappliaction extends appliaction { public document createDocument(){ return new Mydocument(); } }   大家可以看出,这其实使用template method模式,抽象方法声明创建对象,而模板方法完成业务逻辑,她使用抽象创建方法,由继承来获得产品,而不是使用对象来创建对象的。   并且大家仔细看<设计模式>71页的结构图,里的creator里有两个方法,其中一个使用factorymethod方法,另外一个就是普通的方法,anOperation它调用了工厂方法,product=factorymethod()来获得产品对象。   现在问题就出现在这里,而另外一本书阎宏的《java与模式》的167地结构图中却没有把这点作出标记,并且提供的示例,也不像最初<设计模式>中的工厂方法的例子, 他的示例如下: //抽象工厂,而这里却没有方法使用工厂方法: public interface Creator{ /** * 工厂方法 */ public Product factory(); } public class ConcreteCreator1 implements Creator { /** * 工厂方法 */ public Product factory() { return new ConcreteProduct1(); } } 而客户端却使用; public static void main(String[] args){ creator1 = new ConcreteCreator1(); prod1 = creator1.factory(); }   我感觉这样示例有问题,或者不妥,或者不能表达原意。   在客户端,他的对象创建使用了   prod1 = creator1.factory();   这样显然使用对象creator1来创建对象的,而不是使用继承,类模式来完成创建的。这与工厂方法的原意,类模式,把创建工厂延迟到子类实现,等有冲突。   这样想对象创建模式。 <淘宝热门商品:
 

39.00 元  

零售批发*洁丽雅毛巾专卖店*更齐更全更多*更专业

洁丽雅浴巾8464 无捻线,柔软吸水,140*70 390克

 

 

衣品堂


来源:程序员网

小小豆叮

Java技术实现数据库应用系统慨述

Java 语言是Sun MicroSystems 公司于1995年正式命名并推出的一种面向对象的编程语言-OOP(abbr.Object Oriented Programming)。Sun 公司说:Java 程序设计 语言被设计成是 by programmers for programmers,其随着 Internet 的发展而广为流行。用它开发的系统"一次开发,到处运行"的特色以及程序开发设计时所体现出的面向对象的思想深深地触动着人们。它的语言简洁、集多种程序设计语言之大成,且面向对象、具有可移植性、分布性、安全性、高性能等特色。Java在向Internet/Intranet,甚至计算机世界的各个领域渗透,慢慢改变着人们的思维。而今Internet 热浪一浪高过一浪,从外部世界走向企业内部形成Intranet,促进了Java 技术的利用开发。计算机业界中的IBM、ORACAL 、APPLE、Sun、Netscape五家公司还联合推出"网络计算机(NC-1)"规范。抛开"Wintel"臃肿不堪的体系结构,使用户端价格低廉、易于使用,并成为能够连接网络的简单计算机-NC(Network Computer),即所说的"瘦客户"机,NC 支持Java 虚拟机(JVM),能够运行Java开发的应用程序(Application)和小程序(Applet)并支持多媒体应用。NC 和Java 的结合诞生了新的时代:网络计算机时代。就连Sun的冤家对头Microsoft的比尔.盖茨也不得不承认:"Java是长时间以来最卓越的程序设计语言"。   一、 Java 数据库基础 JDBC API   Java语言在数据库应用方面,特别在基于Web 的B/S结构的在线数据库应用方面的烦琐复杂配置等,并不能使用户和程序开发双方都十分满意。SunSoft虽提供了用Java语言编写成的Java与数据库的接口规范JDBC(Java DataBase Connectivity,而JavaSoft说JDBC并不代表什么),使Java程序可以通过统一标准规范的JDBC API来与不同的数据库通信。确保了"100%纯Java"的解决方案。JDBC API 定义了Java中的类和接口,表示数据库连接、SQL 指令、结果集合等。它允许Java程序员发送SQL 指令并处理结果。JDBC API 提供两种主要接口:一是面向开发人员的java.sql程序包,使得Java程序员能够进行数据库连接,执行SQL查询,并得到结果集合。Java2 的java.sql包提供了6个类和18个接口,下文将介绍;另一是面向底层数据库厂商的JDBC Drivers ,目前为止,Java2的JDBC Drivers仅提供下述四种类型的数据库驱动方式,且各有利弊:   (1) JDBC-ODBC bridge plus ODBC driver 方式:JDBC-ODBC 桥接方式利用微软的开放数据库互连接口(ODBC API)同数据库服务器通讯,客户端计算机首先应该安装并配置ODBC driver 和JDBC-ODBC bridge两种驱动程序。这是Applets访问你的数据库最可能的解决方式,但这对Internet 和Intranet 用户而言简直是一个非常令人讨厌和麻烦的解决方案。   (2) Native-API partly Java driver方式:这种驱动方式将数据库厂商的特殊协议转换成Java代码及二进制类码,使Java 数据库客户方与数据库服务器方通信。例如:Oracle用SQLNet协议,DB2用IBM 的数据库协议。数据库厂商的特殊协议也应该被安装在客户机上。这也是令人讨厌和麻烦的解决方案。   (3) JDBC-Net pure Java driver方式:这种方式是纯Java driver。数据库客户以标准网络协议(如HTTP、SHTTP)同数据库访问服务器通信,数据库访问服务器然后翻译标准网络协议成为数据库厂商的专有特殊数据库访问协议(也可能用到ODBC driver)与数据库通信。对Internet 和Intranet 用户而言这是一个理想的解决方案。Java driver 被自动的,以透明的方式随Applets自Web服务器而下载并安装在用户的计算机上。   (4) Native-protocol pure Java driver方式:这种方式也是纯Java driver。数据库厂商提供了特殊的JDBC协议使Java数据库客户与数据库服务器通信。然而,将把代理协议同数据库服务器通信改用数据库厂商的特殊JDBC driver。这对Intranet 应用是高效的,可是数据库厂商的协议可能不被防火墙支持,缺乏防火墙支持在Internet 应用中会存在潜在的安全隐患。   综上四种方式中,只有第三、四种方式的驱动支持 Applet的零安装。因为JDBC drivers 完全用Java 写成,并从Web 服务器上随applet下载。为了支持零安装,驱动程序应该被放在Web上,并与applet 在相同目录。而第四种存在安全隐患,第三种产品为数不多,现今较成熟的IDS JDBC driver属于此种(http://www.idssoftware.com),但也要用到ODBC driver辅助。   即便如此,利用Java技术开发单机环境应用程序,局域网范围或Intranet环境下的应用程序、动态Web应用(Live Intranet)等,Java语言是高效、安全、稳定的。Java语言已赢得了众多厂商的支持,基于其上的Java API-JDBC也发展迅速。Sun承诺任何Java Applet 或Java应用软件都能够与数据库结合,并且仍将不遗余力的支持未来Java技术的发展。Java语言的跨平台特性,使之成为Internet和Intranet环境下开发数据库应用系统的理想选择方案。   二、 Java 的数据库应用开发展望   至此,你已知道:要进行Java 数据库应用程序的设计,需要具备多方面的技能,包括了解或熟练数据库驱动程序、SQL( 结构化查询语言)以及java.sql包所包含的类、接口等。JavaSoft 已经注意到了Java 在数据库程序设计方面的棘手而复杂,他们现在正在开发新的同Java一样容易使用的产品JavaBlend ,该产品将大大简化利用JDBC构建数据库应用系统的过程。JavaBlend 将自动镜像Java 对象成为存储在数据库中的信息。所有对对象的操作,都将产生与之镜像的数据库的动作,包括对存储在数据库中信息的自动查询、更新等。一旦Java 的对象到数据库镜像(Java object-to-database mapping)被成功建立,JavaBlend 将免费发放给Java 程序员,以使Java 程序员从利用繁琐SQL语句、结果集合解决方案过渡到利用JavaBlend 把对Java 对象的方法调用相应地自动转化成SQL语句和结果集合这一简单方案。这将使JDBC和SQL知识在数据库开发时不必考虑过多,而使程序员专心于用户业务方案的提供解决。JavaBlend目前并不包含在JDK 1.2中。   Java 语言及其技术是当今世界程序设计语言的主流。应用Java 技术实现数据库应用系统是未来的发展方向,Java 的数据库应用现已成功地应用于商业、政府及大学等领域,应用才刚刚起步。相信不久的将来,Java 技术将更加完善成熟。Java的数据库应用也将遍地开花。 <淘宝热门商品:
 

3C数码配件 

家倍乐床上笔记本电脑桌专利厂家批发零售店

 

 

黑龙江商盟】棋子儿平价美妆店-烟熏彩妆/假睫毛大全/新娘用品


来源:程序员网

小小豆叮

Java技术实现数据库应用系统慨述

Java 语言是Sun MicroSystems 公司于1995年正式命名并推出的一种面向对象的编程语言-OOP(abbr.Object Oriented Programming)。Sun 公司说:Java 程序设计 语言被设计成是 by programmers for programmers,其随着 Internet 的发展而广为流行。用它开发的系统"一次开发,到处运行"的特色以及程序开发设计时所体现出的面向对象的思想深深地触动着人们。它的语言简洁、集多种程序设计语言之大成,且面向对象、具有可移植性、分布性、安全性、高性能等特色。Java在向Internet/Intranet,甚至计算机世界的各个领域渗透,慢慢改变着人们的思维。而今Internet 热浪一浪高过一浪,从外部世界走向企业内部形成Intranet,促进了Java 技术的利用开发。计算机业界中的IBM、ORACAL 、APPLE、Sun、Netscape五家公司还联合推出"网络计算机(NC-1)"规范。抛开"Wintel"臃肿不堪的体系结构,使用户端价格低廉、易于使用,并成为能够连接网络的简单计算机-NC(Network Computer),即所说的"瘦客户"机,NC 支持Java 虚拟机(JVM),能够运行Java开发的应用程序(Application)和小程序(Applet)并支持多媒体应用。NC 和Java 的结合诞生了新的时代:网络计算机时代。就连Sun的冤家对头Microsoft的比尔.盖茨也不得不承认:"Java是长时间以来最卓越的程序设计语言"。   一、 Java 数据库基础 JDBC API   Java语言在数据库应用方面,特别在基于Web 的B/S结构的在线数据库应用方面的烦琐复杂配置等,并不能使用户和程序开发双方都十分满意。SunSoft虽提供了用Java语言编写成的Java与数据库的接口规范JDBC(Java DataBase Connectivity,而JavaSoft说JDBC并不代表什么),使Java程序可以通过统一标准规范的JDBC API来与不同的数据库通信。确保了"100%纯Java"的解决方案。JDBC API 定义了Java中的类和接口,表示数据库连接、SQL 指令、结果集合等。它允许Java程序员发送SQL 指令并处理结果。JDBC API 提供两种主要接口:一是面向开发人员的java.sql程序包,使得Java程序员能够进行数据库连接,执行SQL查询,并得到结果集合。Java2 的java.sql包提供了6个类和18个接口,下文将介绍;另一是面向底层数据库厂商的JDBC Drivers ,目前为止,Java2的JDBC Drivers仅提供下述四种类型的数据库驱动方式,且各有利弊:   (1) JDBC-ODBC bridge plus ODBC driver 方式:JDBC-ODBC 桥接方式利用微软的开放数据库互连接口(ODBC API)同数据库服务器通讯,客户端计算机首先应该安装并配置ODBC driver 和JDBC-ODBC bridge两种驱动程序。这是Applets访问你的数据库最可能的解决方式,但这对Internet 和Intranet 用户而言简直是一个非常令人讨厌和麻烦的解决方案。   (2) Native-API partly Java driver方式:这种驱动方式将数据库厂商的特殊协议转换成Java代码及二进制类码,使Java 数据库客户方与数据库服务器方通信。例如:Oracle用SQLNet协议,DB2用IBM 的数据库协议。数据库厂商的特殊协议也应该被安装在客户机上。这也是令人讨厌和麻烦的解决方案。   (3) JDBC-Net pure Java driver方式:这种方式是纯Java driver。数据库客户以标准网络协议(如HTTP、SHTTP)同数据库访问服务器通信,数据库访问服务器然后翻译标准网络协议成为数据库厂商的专有特殊数据库访问协议(也可能用到ODBC driver)与数据库通信。对Internet 和Intranet 用户而言这是一个理想的解决方案。Java driver 被自动的,以透明的方式随Applets自Web服务器而下载并安装在用户的计算机上。   (4) Native-protocol pure Java driver方式:这种方式也是纯Java driver。数据库厂商提供了特殊的JDBC协议使Java数据库客户与数据库服务器通信。然而,将把代理协议同数据库服务器通信改用数据库厂商的特殊JDBC driver。这对Intranet 应用是高效的,可是数据库厂商的协议可能不被防火墙支持,缺乏防火墙支持在Internet 应用中会存在潜在的安全隐患。   综上四种方式中,只有第三、四种方式的驱动支持 Applet的零安装。因为JDBC drivers 完全用Java 写成,并从Web 服务器上随applet下载。为了支持零安装,驱动程序应该被放在Web上,并与applet 在相同目录。而第四种存在安全隐患,第三种产品为数不多,现今较成熟的IDS JDBC driver属于此种(http://www.idssoftware.com),但也要用到ODBC driver辅助。   即便如此,利用Java技术开发单机环境应用程序,局域网范围或Intranet环境下的应用程序、动态Web应用(Live Intranet)等,Java语言是高效、安全、稳定的。Java语言已赢得了众多厂商的支持,基于其上的Java API-JDBC也发展迅速。Sun承诺任何Java Applet 或Java应用软件都能够与数据库结合,并且仍将不遗余力的支持未来Java技术的发展。Java语言的跨平台特性,使之成为Internet和Intranet环境下开发数据库应用系统的理想选择方案。   二、 Java 的数据库应用开发展望   至此,你已知道:要进行Java 数据库应用程序的设计,需要具备多方面的技能,包括了解或熟练数据库驱动程序、SQL( 结构化查询语言)以及java.sql包所包含的类、接口等。JavaSoft 已经注意到了Java 在数据库程序设计方面的棘手而复杂,他们现在正在开发新的同Java一样容易使用的产品JavaBlend ,该产品将大大简化利用JDBC构建数据库应用系统的过程。JavaBlend 将自动镜像Java 对象成为存储在数据库中的信息。所有对对象的操作,都将产生与之镜像的数据库的动作,包括对存储在数据库中信息的自动查询、更新等。一旦Java 的对象到数据库镜像(Java object-to-database mapping)被成功建立,JavaBlend 将免费发放给Java 程序员,以使Java 程序员从利用繁琐SQL语句、结果集合解决方案过渡到利用JavaBlend 把对Java 对象的方法调用相应地自动转化成SQL语句和结果集合这一简单方案。这将使JDBC和SQL知识在数据库开发时不必考虑过多,而使程序员专心于用户业务方案的提供解决。JavaBlend目前并不包含在JDK 1.2中。   Java 语言及其技术是当今世界程序设计语言的主流。应用Java 技术实现数据库应用系统是未来的发展方向,Java 的数据库应用现已成功地应用于商业、政府及大学等领域,应用才刚刚起步。相信不久的将来,Java 技术将更加完善成熟。Java的数据库应用也将遍地开花。 <淘宝热门商品:
 

¥:6.98 

四皇冠 值得您收藏的包店 冲五冠 5i贝贝外贸包店◢

◣四冠◆贝妈家◢出口英国★荔枝纹钉扣简约短款钱包◆特价6.99

 

保健品/滋补品 

淑芳阁_苗条姿_最有效的减肥瘦身与丰胸专卖店


来源:程序员网

小小豆叮

关于用JAVA开发短信方面的知识

现在流行的网络业务莫过于短信了.网易新浪等都因此而盈利,股价上涨.我凭自己的经验和公司支持,也就 乘着东风来研究一下了! 首先,你要选择一台移动或者联通的短信服务器做你们的发送短信接口.这是最关键的一步,也是最底层的, 当然这是需要much money的,呵呵.没办法!现实了点.... 然后你就是在连接接口的服务器做技术了.用JAVA 的 SOCKET 来监听客户端的SOCKET,当然这是需要一定的 难度,和普通是有很多的区别,例如每秒钟可以同时接受3000条SOCKET... ...,要进行客户端的认证.要进行数据 流转输的加密... ... 最后就是来处理客户端的发送SOCKET了,其实他们传输都是字节Byte... public class Client { //构造函数 public Client() { connectStatus = false; loginStatus = false; default_ip = ""; default_port = 0; default_user = ""; default_password = ""; connection = null; input = null; out = null; binput = null; } //连接函数 public boolean connect(String ip, int port) { boolean result = false; if(ip == null || ip.indexOf(".") < 1) ip = default_ip; if(port < 1) port = default_port; try { connection = new Socket(ip, port); input = connection.getInputStream(); binput = new BufferedInputStream(input); out = connection.getOutputStream(); result = true; connectStatus = true; default_ip = ip; default_port = port; } catch(Exception e) { result = false; } return result; } //登录函数 public int login(String userName, String password) { int loginRes = -1; if(!connectStatus) return 1; if(userName == null || userName.trim().equals("")) return 24; byte loginData[] = new byte[43]; setIntData(43, loginData, 0); setIntData(1, loginData, 4); setIntData(1, loginData, 8); userName.getBytes(0, userName.length(), loginData, 12); password.getBytes(0, password.length(), loginData, 22); loginData[38] = 1; setTime((new Date()).getTime() / (long)1000, loginData, 39); try { out.write(loginData); out.flush(); byte rec[] = new byte[30]; char ret = '\0'; int i = 0; do { if(i >= 400) break; if(binput.available() > 0) { input.read(rec, 0, 30); ret = (char)rec[12]; break; } Thread.sleep(50L); i++; } while(true); if(ret == 'T') { loginStatus = true; default_user = userName; default_password = password; int k = 0; return k; } loginRes = 1; } catch(Exception e) { int j = 1; return j; } return loginRes; } //发送函数 public int submit(String servicer_id, int msg_type, int status_report, String src_addr, String dest_addr, String schedule, String expire, int msg_fmt, byte msg_content[], String fee_type, String fee_code, String fee_mobile, String fee_by, int pid) { int subRes = -1; if(!connectStatus || !loginStatus) return 1; byte submitData[] = new byte[264]; setIntData(264, submitData, 0); setIntData(4, submitData, 4); setIntData(1, submitData, 8); servicer_id.getBytes(0, servicer_id.length(), submitData, 12); submitData[22] = (byte)msg_type; submitData[23] = (byte)status_report; if(src_addr == null || src_addr.trim().length() < 1) return 14; src_addr.getBytes(0, src_addr.length(), submitData, 24); if(dest_addr == null || dest_addr.trim().length() < 1) return 15; dest_addr.getBytes(0, dest_addr.length(), submitData, 45); if(schedule != null && schedule.trim().length() > 1 && !setTime(schedule, submitData, 66)) return 16; if(expire != null && expire.trim().length() > 1 && !setTime(expire, submitData, 70)) return 17; submitData[74] = (byte)msg_fmt; submitData[75] = (byte)msg_content.length; System.arraycopy(msg_content, 0, submitData, 76, msg_content.length); fee_type.getBytes(0, fee_type.length(), submitData, 236); fee_code.getBytes(0, fee_code.length(), submitData, 244); if(fee_mobile != null && fee_mobile.trim().length() > 11) fee_mobile = fee_mobile.substring(2); fee_mobile.getBytes(0, fee_mobile.length(), submitData, 250); fee_by.getBytes(0, 2, submitData, 261); if(pid < 0 || pid > 256) pid = 0; submitData[263] = (byte)pid; boolean reSend = false; try { out.write(submitData); out.flush(); } catch(Exception e) { reSend = true; } if(reSend) { int sendTimes = 0; do { if(sendTimes >= 2) break; try { connect(default_ip, default_port); login(default_user, default_password); out.write(submitData); out.flush(); reSend = false; break; } catch(Exception exception) { sendTimes++; } } while(true); } if(reSend) { connectStatus = false; loginStatus = false; return 1; } try { byte sub[] = new byte[17]; char sRet = '\0'; int i = 0; do { if(i >= 1500) break; if(binput.available() > 0) { input.read(sub, 0, 17); sRet = (char)sub[16]; break; } Thread.sleep(10L); i++; } while(true); if(sRet == 'T') subRes = 0; else subRes = 11; } catch(Exception e) { subRes = 1; } return subRes; } 当然要根据不同的参数来判断不同的错误和正确的发送.就谈这么多了,如果大家有什么不明的,可以和我联系. 作者简介: 22岁,大学计算机系专业,现正致力于JAVA开发,对JAVA的桌面应用系统开发和WEB相关技术有一定研究, 曾开发jant,jzip,小型游戏,JDBC..etc,对J2EE/J2ME充满信心。 你可以通过网站:http://www.fls-cts.com/kkjvk/、 OICQ:29578635,878229,email:kkjvk12@yeah.net和vincent联系。 <淘宝热门商品:
 

 

【广州商盟】意外金喜服装◎抵制暴利低价有好货◎收藏小店有惊喜

 

¥:59.90 

天使之城外贸服装商行(童装/女装)【双皇冠网店 实体店同步】

双皇冠!韩国安卡米文静米色提花高领毛衣,专柜236元,140码


来源:程序员网

小小豆叮

jfreechart中标题的中文显示问题

先找到jfreechart源文件中的JFreeChartConstants.java,修改默认字体为: public static final Font DEFAULT_TITLE_FONT = new Font("黑体", Font.BOLD, 18);然后重新编译,成功后更新到jfreechart-0.9.8.jar中。 现在你可以随便的setTitle(string)了。 别的地方字体怎么改,大家一起研究吧。 <淘宝热门商品:
 

¥:89.00 

爱相依外贸童装.精品低价.15天无理由退货

特价 贺年款 精美棉大衣外套/棉衣/棉袄 帽子可拆卸 3971

 

188.00 元  

地球都踩在脚下

T-MAC8麦迪8代 麦8 08-09赛季麦迪篮球鞋 白黑红 阿迪达斯adidas


来源:程序员网

小小豆叮

将j2me和j2ee结合,结合GPS!

将j2me技术和j2ee技术整合在一起,多种终端设备,实现移动设备和pc接入的通信。 在现有阶段,移动设备可以通过短信方式作为一种手段传送数据,以后可以使用其他方式, 加上GPS和地图供应商,我们可以达到现有呼叫中心,gis系统,以及其他很多系统的功能, 移动设备开发将会大大降低开发成本,产品研发已小有成果,借此处寻求投资商:我是本站的wills,13337835824,robertma@prient.com <淘宝热门商品:
 

 

天使名妆 08日韩版秋季OL洋装平价针织2件包邮 时尚only韩国代购

 

88.00 元  

【广州商盟】外贸男装、男鞋工厂直接供货批发零售

〖亿贝特价〗外贸原单Versace范思哲多LOGO特色羊毛衫、毛衣V灰紫


来源:程序员网

小小豆叮

用line_as_stream 简化流的读取

在将数据持久化到文件时,你可能会发现很难强制要求系统将特定的部分数据写到一行中。将特定的数据写到同一行有时是很有用的,比如在你从流(如一个文件)中读取一个数组的时候。 假设你要读取一个数组的元素,其中有一行被破坏了(比如丢失了一些数据)。一般情况下,这会导致后面所有的元素都受损。 作为一个例子,假设我们有一个数据结构,是一个窗口数组,你希望把它持久化到一个文件中,象下面这样: 第一行:窗口的数量 后面的每一行都包含两个值:窗口的宽度和窗口的高度 写成代码似乎很简单: #include #include #include struct Window { Window( int nLength = 0, int nHeight = 0) : m_nWindowLength( nLength), m_nWindowHeight( nHeight) {} int m_nWindowLength; int m_nWindowHeight; }; std::ostream & operator << ( std::ostream & streamOut, const Window & value) { streamOut << value.m_nWindowLength << " " << value.m_nWindowHeight; return streamOut; } std::istream & operator >> ( std::istream & streamIn, Window & value) { streamIn >> value.m_nWindowLength >> value.m_nWindowHeight; return streamIn; } void write_windows( std::vector< Window> &aWindows, const char * strFileName) { std::ofstream streamOut( strFileName); // 第一行 streamOut << aWindows.size() << std::endl; // 其余行 std::vector< Window>::iterator itFirst = aWindows.begin(), itLast = aWindows.end(); while ( itFirst != itLast) { // 每个窗口的数据都在它自己那一行 streamOut << *itFirst << std::endl; ++itFirst; } } 但是,要正确地读出这些数据,可能会有一些问题: //可能出错!!! void read_windows( std::vector< Window> &aWindows, const char * strFileName) { aWindows.clear(); std::ifstream streamIn( strFileName); int nSize; streamIn >> nSize; for ( int idx = 0; idx < nSize; ++idx) { Window w; streamIn >> w; aWindows.push_back( w); } } 上面的代码并没有强制任何东西。所有数据都被放到一行中,这看起来没有什么问题。但如果用户不小心,修改了你的文件,插入了一个多余的值或删掉了一个值,那么后面所有的元素都会得到错误的值,而你的程序并不会意识到这一点。尝试运行一下下面的代码并仔细看看其中的注释: #include #include int main(int argc, char* argv[]) { std::vector< Window> aWindows; aWindows.push_back( Window( 100, 400)); aWindows.push_back( Window( 200, 400)); aWindows.push_back( Window( 400, 400)); aWindows.push_back( Window( 500, 500)); aWindows.push_back( Window( 600, 200)); aWindows.push_back( Window( 600, 400)); aWindows.push_back( Window( 600, 690)); write_windows( aWindows, "persist.txt"); std::vector< Window> aReadWindows; /* 在这里加一个调试断点; 修改persist.txt,删除第4行的第一个值*/ read_windows( aReadWindows, "persist.txt"); std::copy( aReadWindows.begin(), aReadWindows.end(), std::ostream_iterator< Window>( std::cout, "\n")); /*在这里加一个调试断点:看看你读了多少个错误的值! */ return 0; } 还好,你可以用来line_as_stream读取一行,然后将它看作一个流。用这种方法,你可以确定每个元素是从一行中读取的。于是,read_windows函数变成这样: void read_windows( std::vector< Window> &aWindows, const char * strFileName) { aWindows.clear(); std::ifstream streamIn( strFileName); int nSize; // 第一行 line_as_stream( streamIn) >> nSize; for ( int idx = 0; idx < nSize; ++idx) { Window w; //每个窗口的数据都在它自己那一行 line_as_stream( streamIn) >> w; aWindows.push_back( w); } } 现在,重新运行前面的例子,你可以看到只有一个元素受损,如你所料。 这就是line_as_stream的源码: #include #include #include namespace Private { template< class char_type, class char_traits> struct line_stream_holder { typedef line_stream_holder< char_type, char_traits> this_class; typedef std::basic_istringstream< char_type, char_traits> stream_type; typedef std::basic_string< char_type, char_traits> string_type; line_stream_holder( const string_type & value) : m_stream( value) {} line_stream_holder( const this_class & source) : m_stream( source.m_stream.str() ) {} // allow passing this stream in functions that // accept streams operator stream_type & () const { return m_stream; } private: mutable stream_type m_stream; }; template< class char_type, class char_traits, class value_type> inline typename line_stream_holder< char_type, char_traits>::stream_type & operator >> (const line_stream_holder< char_type, char_traits> & streamIn, value_type & value) { typedef typename line_stream_holder< char_type, char_traits>::stream_type stream_type; stream_type & underlyingStream = streamIn; underlyingStream >> value; return underlyingStream; } } // namespace Private template< class char_type, class char_traits> Private::line_stream_holder< char_type, char_traits> line_as_stream( std::basic_istream< char_type, char_traits> & streamIn, char_type chDelim = '\n') { std::basic_string< char_type, char_traits> strLine; std::getline( streamIn, strLine, chDelim); return strLine; } <淘宝热门商品:
 

95.00 元  

韩国正品专卖!Intercrew LED手表/男

 

199.00 元  

JACK JONES专柜正品白色内绒毛设计羊毛毛


来源:程序员网

小小豆叮

学习用于异常处理的terminate()函数

异常处理是一个微妙的问题,你应该尽可能优雅地处理所有异常。要达到这个目的,你需要学习terminate()函数。 terminate()函数在程序抛出一个异常并且异常没有被捕获的时候被调用,像下面这样: #include #include void on_terminate() { std::cout << "terminate() 函数被调用了!" << std::endl; std::cin.get(); } int main() { // 如果用 VC6,去掉“std::”前缀 std::set_terminate( on_terminate); throw std::exception(); std::cout << "terminate() 函数没有被调用!" << std::endl; std::cin.get(); return 0; } 避免这种情形的方案一开始看起来很简单: int main() { try { /* code */ } catch( std::exception & exc) { // 记录到日志,或作其他处理 } catch(...) { // 记录下“Unknown exception” } return 0; } 不过,在多线程应用程序中情况变得有点复杂,因为你创建的每个线程都要有上面的(catch)处理过程。 然而terminate()函数在许多其它情况下会被调用,包括: 当你抛出一个异常,并且在它的拷贝构造函数中,另一个异常被抛出。 在堆栈展开的过程中抛出一个异常,此时析构函数抛出一个异常。 当一个静态对象的构造函数或析构函数抛出异常时。 当一个用atexit注册过的函数抛出一个异常时。 当你在代码中写下“throw;”(这意味着重新抛出当前异常),然而并没有当前异常时。 当一个函数抛出一个它的异常说明不允许的异常时 当默认的unexpected()处理过程被调用时 下面的代码演示了上面各种情况下的结果: #include #include void on_terminate() { std::cout << "terminate()函数被调用了!" << std::endl; std::cin.get(); } //////////////////////////////// [1] struct custom_exception { custom_exception() {} custom_exception( const custom_exception &) { throw std::exception(); } }; void case_1() { try { throw custom_exception(); } catch(...) {} } //////////////////////////////// [2] struct throw_in_destructor { ~throw_in_destructor() { throw std::exception(); } }; void case_2() { try { throw_in_destructor temp; throw std::exception(); } catch(...) {} } //////////////////////////////// [3] struct static_that_throws { static_that_throws() { throw std::exception(); } }; void case_3() { // 注意:用try/catch块包围下面的代码并不起作用 static static_that_throws obj; } //////////////////////////////// [4] void throw_at_exit() { throw std::exception(); } void case_4() { atexit( throw_at_exit); } //////////////////////////////// [5] void case_5() { throw; } //////////////////////////////// [6] class custom_6_a {}; class custom_6_b {}; void func_violating_exception_specification_6() throw(std::exception) { throw custom_6_a(); } // 注意:按照我们的例子,在这个函数中我们只应该抛出 // std::exception(在函数func_violating_exception_specification // 的定义中说明的异常);但我们没有这样做, // 因此,terminate() 被调用 void on_unexpected() { throw custom_6_b(); } void case_6() { std::set_unexpected( on_unexpected); try { func_violating_exception_specification_6(); } catch(...) {} } //////////////////////////////// [7] class custom_7 {}; void func_violating_exception_specification_7() throw(std::exception) { throw custom_7(); } void case_7() { try { func_violating_exception_specification_7(); } catch(...) {} } int main() { std::set_terminate( on_terminate); // 注意:确保每次仅去掉下面一个调用的注释, // 以便分析时将每种情况隔离开来 case_1(); // case_2(); // case_3(); // case_4(); // case_5(); // case_6(); // case_7(); return 0; } 尽管你应该努力避免terminate()函数会被调用的情况,我们还是建议你创建自己的terminate()处理过程。你的处理过程要做的唯一合理的事是记录一条消息到日志中。不管怎样,确保你的日志不会抛出任何异常。 std::ostream& get_log() { /* code */ } void on_terminate() { std::ostream & log = get_log(); // 确保我们不会抛出任何东西! try { log.exceptions( std::ios_base::goodbit); } catch (...) {} log << "terminate() 被调用了!" << std::endl; } int main() { std::set_terminate( on_terminate) ; // . . . } <淘宝热门商品:
 

17.80 元  

居家家--18个月上四皇冠,家居类信用最高卖家

简家 四皇冠信用 鲸鱼USB暖手鼠标垫D4063 冬天上网必备

 

0.90 元  

:①般般dē我 开【不】①般般的店

『四钻信誉』官方QB正规秒冲Q币,按元直充0.9元/QQ币


来源:程序员网

小小豆叮

在Java中实现回调过程

摘要: Java接口提供了一个很好的方法来实现回调函数。如果你习惯于在事件驱动的编程模型中,通过传递函数指针来调用方法达到目的的话,那么你就会喜欢这个技巧。 作者:John D. Mitchell 在MS-Windows或者X-Window系统的事件驱动模型中,当某些事件发生的时候,开发人员已经熟悉通过传递函数指针来调用处理方法。而在Java的面向对象的模型中,不能支持这种方法,因而看起来好像排除了使用这种比较舒服的机制,但事实并非如此。 Java的接口提供了一种很好的机制来让我们达到和回调相同的效果。这个诀窍就在于定一个简单的接口,在接口之中定义一个我们希望调用的方法。 举个例子来说,假设当一个事件发生的时候,我们想它被通知,那么我们定义一个接口: public interface InterestingEvent { // This is just a regular method so it can return something or // take arguments if you like. public void interestingEvent (); } 这就给我们一个控制实现了该接口的所有类的对象的控制点。因此,我们不需要关心任何和自己相关的其它外界的类型信息。这种方法比C函数更好,因为在C++风格的代码中,需要指定一个数据域来保存对象指针,而Java中这种实现并不需要。 发出事件的类需要对象实现InterestingEvent接口,然后调用接口中的interestingEvent ()方法。 public class EventNotifier { private InterestingEvent ie; private boolean somethingHappened; public EventNotifier (InterestingEvent event) { // Save the event object for later use. ie = event; // Nothing to report yet. somethingHappened = false; } //... public void doWork () { // Check the predicate, which is set elsewhere. if (somethingHappened) { // Signal the even by invoking the interface's method. ie.interestingEvent (); } //... } // ... } 在这个例子中,我们使用了somethingHappened这个标志来跟踪是否事件应该被激发。在许多事例中,被调用的方法能够激发interestingEvent()方法才是正确的。 希望收到事件通知的代码必须实现InterestingEvent接口,并且正确的传递自身的引用到事件通知器。 public class CallMe implements InterestingEvent { private EventNotifier en; public CallMe () { // Create the event notifier and pass ourself to it. en = new EventNotifier (this); } // Define the actual handler for the event. public void interestingEvent () { // Wow! Something really interesting must have occurred! // Do something... } //... } 希望这点小技巧能给你带来方便。 关于作者: John D. Mitchell在过去的九年内一直做顾问,曾经在Geoworks使用OO汇编语言开发了PDA软件,兴趣于写编译器,Tcl/Tk和Java系统。和人合著了《Making Sense of Java》,目前从事Java编译器的工作。 <淘宝热门商品:
 

136.00 元  

达人公社 专柜正品 纽巴伦 newbalance 匡威 crocs折扣 店

正品 日版纽巴伦new balance 型号:TK02 深灰黑

 

105.00 元 

Levi's 复古铜系列情侣款女装牛仔裤


来源:程序员网

小小豆叮