﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-成长中的记忆-文章分类-JSP</title><link>http://www.blogjava.net/aiyoyoyo/category/7534.html</link><description>这是我的成长，这是我的天地，学习JAVA，只因快乐。</description><language>zh-cn</language><lastBuildDate>Thu, 01 Mar 2007 18:24:59 GMT</lastBuildDate><pubDate>Thu, 01 Mar 2007 18:24:59 GMT</pubDate><ttl>60</ttl><item><title>Java Servlet连接池的方法</title><link>http://www.blogjava.net/aiyoyoyo/articles/31225.html</link><dc:creator>aiyoyoyo</dc:creator><author>aiyoyoyo</author><pubDate>Fri, 17 Feb 2006 08:43:00 GMT</pubDate><guid>http://www.blogjava.net/aiyoyoyo/articles/31225.html</guid><wfw:comment>http://www.blogjava.net/aiyoyoyo/comments/31225.html</wfw:comment><comments>http://www.blogjava.net/aiyoyoyo/articles/31225.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/aiyoyoyo/comments/commentRss/31225.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/aiyoyoyo/services/trackbacks/31225.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;Java&nbsp;Servlet作为首选的服务器端数据处理技术，正在迅速取代CGI脚本。Servlet超越CGI的优势之一在于，不仅多个请求可以共享公用资源，而且还可以在不同用户请求之间保留持续数据。本文介绍一种充分发挥该特色的实用技术，即数据库连接池。&nbsp;<BR><BR><BR>一、实现连接池的意义&nbsp;<BR><BR>动态Web站点往往用数据库存储的信息生成Web页面，每一个页面请求导致一次数据库访问。连接数据库不仅要开销一定的通讯和内存资源，还必须完成用户验证、安全上下文配置这类任务，因而往往成为最为耗时的操作。当然，实际的连接时间开销千变万化，但1到2秒延迟并非不常见。如果某个基于数据库的Web应用只需建立一次初始连接，不同页面请求能够共享同一连接，就能获得显著的性能改善。&nbsp;<BR>Servlet是一个Java类。Servlet引擎（它可能是Web服务软件的一部分，也可能是一个独立的附加模块）在系统启动或Servlet第一次被请求时将该类装入Java虚拟机并创建它的一个实例。不同用户请求由同一Servlet实例的多个独立线程处理。那些要求在不同请求之间持续有效的数据既可以用Servlet的实例变量来保存，也可以保存在独立的辅助对象中。&nbsp;<BR>用JDBC访问数据库首先要创建与数据库之间的连接，获得一个连接对象（Connection），由连接对象提供执行SQL语句的方法。本文介绍的数据库连接池包括一个管理类DBConnectionManager，负责提供与多个连接池对象（DBConnectionPool类）之间的接口。每一个连接池对象管理一组JDBC连接对象，每一个连接对象可以被任意数量的Servlet共享。&nbsp;<BR>类DBConnectionPool提供以下功能：&nbsp;<BR><BR>1)&nbsp;从连接池获取（或创建）可用连接。&nbsp;<BR>2)&nbsp;把连接返回给连接池。&nbsp;<BR>3)&nbsp;在系统关闭时释放所有资源，关闭所有连接。&nbsp;<BR><BR>此外，&nbsp;DBConnectionPool类还能够处理无效连接（原来登记为可用的连接，由于某种原因不再可用，如超时，通讯问题），并能够限制连接池中的连接总数不超过某个预定值。&nbsp;<BR>管理类DBConnectionManager用于管理多个连接池对象，它提供以下功能：&nbsp;<BR><BR>1)&nbsp;装载和注册JDBC驱动程序。&nbsp;<BR>2)&nbsp;根据在属性文件中定义的属性创建连接池对象。&nbsp;<BR>3)&nbsp;实现连接池名字与其实例之间的映射。&nbsp;<BR>4)&nbsp;跟踪客户程序对连接池的引用，保证在最后一个客户程序结束时安全地关闭所有连接池。&nbsp;<BR><BR>本文余下部分将详细说明这两个类，最后给出一个示例演示Servlet使用连接池的一般过程。&nbsp;<BR><BR><BR>二、具体实现&nbsp;<BR><BR>DBConnectionManager.java程序清单如下：&nbsp;<BR><BR>001&nbsp;import&nbsp;java.io.*;<BR>002&nbsp;import&nbsp;java.sql.*;<BR>003&nbsp;import&nbsp;java.util.*;<BR>004&nbsp;import&nbsp;java.util.Date;<BR>005&nbsp;<BR>006&nbsp;/**&nbsp;<BR>007&nbsp;*&nbsp;管理类DBConnectionManager支持对一个或多个由属性文件定义的数据库连接&nbsp;<BR>008&nbsp;*&nbsp;池的访问.客户程序可以调用getInstance()方法访问本类的唯一实例.&nbsp;<BR>009&nbsp;*/&nbsp;<BR>010&nbsp;public&nbsp;class&nbsp;DBConnectionManager&nbsp;{&nbsp;<BR>011&nbsp;static&nbsp;private&nbsp;DBConnectionManager&nbsp;instance;//&nbsp;唯一实例&nbsp;<BR>012&nbsp;static&nbsp;private&nbsp;int&nbsp;clients;<BR>013&nbsp;<BR>014&nbsp;private&nbsp;Vector&nbsp;drivers&nbsp;=&nbsp;new&nbsp;Vector();<BR>015&nbsp;private&nbsp;PrintWriter&nbsp;log;<BR>016&nbsp;private&nbsp;Hashtable&nbsp;pools&nbsp;=&nbsp;new&nbsp;Hashtable();<BR>017&nbsp;<BR>018&nbsp;/**&nbsp;<BR>019&nbsp;*&nbsp;返回唯一实例.如果是第一次调用此方法,则创建实例&nbsp;<BR>020&nbsp;*&nbsp;<BR>021&nbsp;*&nbsp;@return&nbsp;DBConnectionManager&nbsp;唯一实例&nbsp;<BR>022&nbsp;*/&nbsp;<BR>023&nbsp;static&nbsp;synchronized&nbsp;public&nbsp;DBConnectionManager&nbsp;getInstance()&nbsp;{&nbsp;<BR>024&nbsp;if&nbsp;(instance&nbsp;==&nbsp;null)&nbsp;{&nbsp;<BR>025&nbsp;instance&nbsp;=&nbsp;new&nbsp;DBConnectionManager();<BR>026&nbsp;}&nbsp;<BR>027&nbsp;clients++;<BR>028&nbsp;return&nbsp;instance;<BR>029&nbsp;}&nbsp;<BR>030&nbsp;<BR>031&nbsp;/**&nbsp;<BR>032&nbsp;*&nbsp;建构函数私有以防止其它对象创建本类实例&nbsp;<BR>033&nbsp;*/&nbsp;<BR>034&nbsp;private&nbsp;DBConnectionManager()&nbsp;{&nbsp;<BR>035&nbsp;init();<BR>036&nbsp;}&nbsp;<BR>037&nbsp;<BR>038&nbsp;/**&nbsp;<BR>039&nbsp;*&nbsp;将连接对象返回给由名字指定的连接池&nbsp;<BR>040&nbsp;*&nbsp;<BR>041&nbsp;*&nbsp;@param&nbsp;name&nbsp;在属性文件中定义的连接池名字&nbsp;<BR>042&nbsp;*&nbsp;@param&nbsp;con&nbsp;连接对象&nbsp;<BR>043&nbsp;*/&nbsp;<BR>044&nbsp;public&nbsp;void&nbsp;freeConnection(String&nbsp;name,&nbsp;Connection&nbsp;con)&nbsp;{&nbsp;<BR>045&nbsp;DBConnectionPool&nbsp;pool&nbsp;=&nbsp;(DBConnectionPool)&nbsp;pools.get(name);<BR>046&nbsp;if&nbsp;(pool&nbsp;!=&nbsp;null)&nbsp;{&nbsp;<BR>047&nbsp;pool.freeConnection(con);<BR>048&nbsp;}&nbsp;<BR>049&nbsp;}&nbsp;<BR>050&nbsp;<BR>051&nbsp;/**&nbsp;<BR>052&nbsp;*&nbsp;获得一个可用的(空闲的)连接.如果没有可用连接,且已有连接数小于最大连接数&nbsp;<BR>053&nbsp;*&nbsp;限制,则创建并返回新连接&nbsp;<BR>054&nbsp;*&nbsp;<BR>055&nbsp;*&nbsp;@param&nbsp;name&nbsp;在属性文件中定义的连接池名字&nbsp;<BR>056&nbsp;*&nbsp;@return&nbsp;Connection&nbsp;可用连接或null&nbsp;<BR>057&nbsp;*/&nbsp;<BR>058&nbsp;public&nbsp;Connection&nbsp;getConnection(String&nbsp;name)&nbsp;{&nbsp;<BR>059&nbsp;DBConnectionPool&nbsp;pool&nbsp;=&nbsp;(DBConnectionPool)&nbsp;pools.get(name);<BR>060&nbsp;if&nbsp;(pool&nbsp;!=&nbsp;null)&nbsp;{&nbsp;<BR>061&nbsp;return&nbsp;pool.getConnection();<BR>062&nbsp;}&nbsp;<BR>063&nbsp;return&nbsp;null;<BR>064&nbsp;}&nbsp;<BR>065&nbsp;<BR>066&nbsp;/**&nbsp;<BR>067&nbsp;*&nbsp;获得一个可用连接.若没有可用连接,且已有连接数小于最大连接数限制,&nbsp;<BR>068&nbsp;*&nbsp;则创建并返回新连接.否则,在指定的时间内等待其它线程释放连接.&nbsp;<BR>069&nbsp;*&nbsp;<BR>070&nbsp;*&nbsp;@param&nbsp;name&nbsp;连接池名字&nbsp;<BR>071&nbsp;*&nbsp;@param&nbsp;time&nbsp;以毫秒计的等待时间&nbsp;<BR>072&nbsp;*&nbsp;@return&nbsp;Connection&nbsp;可用连接或null&nbsp;<BR>073&nbsp;*/&nbsp;<BR>074&nbsp;public&nbsp;Connection&nbsp;getConnection(String&nbsp;name,&nbsp;long&nbsp;time)&nbsp;{&nbsp;<BR>075&nbsp;DBConnectionPool&nbsp;pool&nbsp;=&nbsp;(DBConnectionPool)&nbsp;pools.get(name);<BR>076&nbsp;if&nbsp;(pool&nbsp;!=&nbsp;null)&nbsp;{&nbsp;<BR>077&nbsp;return&nbsp;pool.getConnection(time);<BR>078&nbsp;}&nbsp;<BR>079&nbsp;return&nbsp;null;<BR>080&nbsp;}&nbsp;<BR>081&nbsp;<BR>082&nbsp;/**&nbsp;<BR>083&nbsp;*&nbsp;关闭所有连接,撤销驱动程序的注册&nbsp;<BR>084&nbsp;*/&nbsp;<BR>085&nbsp;public&nbsp;synchronized&nbsp;void&nbsp;release()&nbsp;{&nbsp;<BR>086&nbsp;//&nbsp;等待直到最后一个客户程序调用&nbsp;<BR>087&nbsp;if&nbsp;(--clients&nbsp;!=&nbsp;0)&nbsp;{&nbsp;<BR>088&nbsp;return;<BR>089&nbsp;}&nbsp;<BR>090&nbsp;<BR>091&nbsp;Enumeration&nbsp;allPools&nbsp;=&nbsp;pools.elements();<BR>092&nbsp;while&nbsp;(allPools.hasMoreElements())&nbsp;{&nbsp;<BR>093&nbsp;DBConnectionPool&nbsp;pool&nbsp;=&nbsp;(DBConnectionPool)&nbsp;allPools.nextElement();<BR>094&nbsp;pool.release();<BR>095&nbsp;}&nbsp;<BR>096&nbsp;Enumeration&nbsp;allDrivers&nbsp;=&nbsp;drivers.elements();<BR>097&nbsp;while&nbsp;(allDrivers.hasMoreElements())&nbsp;{&nbsp;<BR>098&nbsp;Driver&nbsp;driver&nbsp;=&nbsp;(Driver)&nbsp;allDrivers.nextElement();<BR>099&nbsp;try&nbsp;{&nbsp;<BR>100&nbsp;DriverManager.deregisterDriver(driver);<BR>101&nbsp;log("撤销JDBC驱动程序&nbsp;"&nbsp;+&nbsp;driver.getClass().getName()+"的注册");<BR>102&nbsp;}&nbsp;<BR>103&nbsp;catch&nbsp;(SQLException&nbsp;e)&nbsp;{&nbsp;<BR>104&nbsp;log(e,&nbsp;"无法撤销下列JDBC驱动程序的注册:&nbsp;"&nbsp;+&nbsp;driver.getClass().getName());<BR>105&nbsp;}&nbsp;<BR>106&nbsp;}&nbsp;<BR>107&nbsp;}&nbsp;<BR>108&nbsp;<BR>109&nbsp;/**&nbsp;<BR>110&nbsp;*&nbsp;根据指定属性创建连接池实例.&nbsp;<BR>111&nbsp;*&nbsp;<BR>112&nbsp;*&nbsp;@param&nbsp;props&nbsp;连接池属性&nbsp;<BR>113&nbsp;*/&nbsp;<BR>114&nbsp;private&nbsp;void&nbsp;createPools(Properties&nbsp;props)&nbsp;{&nbsp;<BR>115&nbsp;Enumeration&nbsp;propNames&nbsp;=&nbsp;props.propertyNames();<BR>116&nbsp;while&nbsp;(propNames.hasMoreElements())&nbsp;{&nbsp;<BR>117&nbsp;String&nbsp;name&nbsp;=&nbsp;(String)&nbsp;propNames.nextElement();<BR>118&nbsp;if&nbsp;(name.endsWith(".url"))&nbsp;{&nbsp;<BR>119&nbsp;String&nbsp;poolName&nbsp;=&nbsp;name.substring(0,&nbsp;name.lastIndexOf("."));<BR>120&nbsp;String&nbsp;url&nbsp;=&nbsp;props.getProperty(poolName&nbsp;+&nbsp;".url");<BR>121&nbsp;if&nbsp;(url&nbsp;==&nbsp;null)&nbsp;{&nbsp;<BR>122&nbsp;log("没有为连接池"&nbsp;+&nbsp;poolName&nbsp;+&nbsp;"指定URL");<BR>123&nbsp;continue;<BR>124&nbsp;}&nbsp;<BR>125&nbsp;String&nbsp;user&nbsp;=&nbsp;props.getProperty(poolName&nbsp;+&nbsp;".user");<BR>126&nbsp;String&nbsp;password&nbsp;=&nbsp;props.getProperty(poolName&nbsp;+&nbsp;".password");<BR>127&nbsp;String&nbsp;maxconn&nbsp;=&nbsp;props.getProperty(poolName&nbsp;+&nbsp;".maxconn",&nbsp;"0");<BR>128&nbsp;int&nbsp;max;<BR>129&nbsp;try&nbsp;{&nbsp;<BR>130&nbsp;max&nbsp;=&nbsp;Integer.valueOf(maxconn).intValue();<BR>131&nbsp;}&nbsp;<BR>132&nbsp;catch&nbsp;(NumberFormatException&nbsp;e)&nbsp;{&nbsp;<BR>133&nbsp;log("错误的最大连接数限制:&nbsp;"&nbsp;+&nbsp;maxconn&nbsp;+&nbsp;"&nbsp;.连接池:&nbsp;"&nbsp;+&nbsp;poolName);<BR>134&nbsp;max&nbsp;=&nbsp;0;<BR>135&nbsp;}&nbsp;<BR>136&nbsp;DBConnectionPool&nbsp;pool&nbsp;=&nbsp;<BR>137&nbsp;new&nbsp;DBConnectionPool(poolName,&nbsp;url,&nbsp;user,&nbsp;password,&nbsp;max);<BR>138&nbsp;pools.put(poolName,&nbsp;pool);<BR>139&nbsp;log("成功创建连接池"&nbsp;+&nbsp;poolName);<BR>140&nbsp;}&nbsp;<BR>141&nbsp;}&nbsp;<BR>142&nbsp;}&nbsp;<BR>143&nbsp;<BR>144&nbsp;/**&nbsp;<BR>145&nbsp;*&nbsp;读取属性完成初始化&nbsp;<BR>146&nbsp;*/&nbsp;<BR>147&nbsp;private&nbsp;void&nbsp;init()&nbsp;{&nbsp;<BR>148&nbsp;InputStream&nbsp;is&nbsp;=&nbsp;getClass().getResourceAsStream("/db.properties");<BR>149&nbsp;Properties&nbsp;dbProps&nbsp;=&nbsp;new&nbsp;Properties();<BR>150&nbsp;try&nbsp;{&nbsp;<BR>151&nbsp;dbProps.load(is);<BR>152&nbsp;}&nbsp;<BR>153&nbsp;catch&nbsp;(Exception&nbsp;e)&nbsp;{&nbsp;<BR>154&nbsp;System.err.println("不能读取属性文件.&nbsp;"&nbsp;+&nbsp;<BR>155&nbsp;"请确保db.properties在CLASSPATH指定的路径中");<BR>156&nbsp;return;<BR>157&nbsp;}&nbsp;<BR>158&nbsp;String&nbsp;logFile&nbsp;=&nbsp;dbProps.getProperty("logfile",&nbsp;"DBConnectionManager.log");<BR>159&nbsp;try&nbsp;{&nbsp;<BR>160&nbsp;log&nbsp;=&nbsp;new&nbsp;PrintWriter(new&nbsp;FileWriter(logFile,&nbsp;true),&nbsp;true);<BR>161&nbsp;}&nbsp;<BR>162&nbsp;catch&nbsp;(IOException&nbsp;e)&nbsp;{&nbsp;<BR>163&nbsp;System.err.println("无法打开日志文件:&nbsp;"&nbsp;+&nbsp;logFile);<BR>164&nbsp;log&nbsp;=&nbsp;new&nbsp;PrintWriter(System.err);<BR>165&nbsp;}&nbsp;<BR>166&nbsp;loadDrivers(dbProps);<BR>167&nbsp;createPools(dbProps);<BR>168&nbsp;}&nbsp;<BR>169&nbsp;<BR>170&nbsp;/**&nbsp;<BR>171&nbsp;*&nbsp;装载和注册所有JDBC驱动程序&nbsp;<BR>172&nbsp;*&nbsp;<BR>173&nbsp;*&nbsp;@param&nbsp;props&nbsp;属性&nbsp;<BR>174&nbsp;*/&nbsp;<BR>175&nbsp;private&nbsp;void&nbsp;loadDrivers(Properties&nbsp;props)&nbsp;{&nbsp;<BR>176&nbsp;String&nbsp;driverClasses&nbsp;=&nbsp;props.getProperty("drivers");<BR>177&nbsp;StringTokenizer&nbsp;st&nbsp;=&nbsp;new&nbsp;StringTokenizer(driverClasses);<BR>178&nbsp;while&nbsp;(st.hasMoreElements())&nbsp;{&nbsp;<BR>179&nbsp;String&nbsp;driverClassName&nbsp;=&nbsp;st.nextToken().trim();<BR>180&nbsp;try&nbsp;{&nbsp;<BR>181&nbsp;Driver&nbsp;driver&nbsp;=&nbsp;(Driver)&nbsp;<BR>182&nbsp;Class.forName(driverClassName).newInstance();<BR>183&nbsp;DriverManager.registerDriver(driver);<BR>184&nbsp;drivers.addElement(driver);<BR>185&nbsp;log("成功注册JDBC驱动程序"&nbsp;+&nbsp;driverClassName);<BR>186&nbsp;}&nbsp;<BR>187&nbsp;catch&nbsp;(Exception&nbsp;e)&nbsp;{&nbsp;<BR>188&nbsp;log("无法注册JDBC驱动程序:&nbsp;"&nbsp;+&nbsp;<BR>189&nbsp;driverClassName&nbsp;+&nbsp;",&nbsp;错误:&nbsp;"&nbsp;+&nbsp;e);<BR>190&nbsp;}&nbsp;<BR>191&nbsp;}&nbsp;<BR>192&nbsp;}&nbsp;<BR>193&nbsp;<BR>194&nbsp;/**&nbsp;<BR>195&nbsp;*&nbsp;将文本信息写入日志文件&nbsp;<BR>196&nbsp;*/&nbsp;<BR>197&nbsp;private&nbsp;void&nbsp;log(String&nbsp;msg)&nbsp;{&nbsp;<BR>198&nbsp;log.println(new&nbsp;Date()&nbsp;+&nbsp;":&nbsp;"&nbsp;+&nbsp;msg);<BR>199&nbsp;}&nbsp;<BR>200&nbsp;<BR>201&nbsp;/**&nbsp;<BR>202&nbsp;*&nbsp;将文本信息与异常写入日志文件&nbsp;<BR>203&nbsp;*/&nbsp;<BR>204&nbsp;private&nbsp;void&nbsp;log(Throwable&nbsp;e,&nbsp;String&nbsp;msg)&nbsp;{&nbsp;<BR>205&nbsp;log.println(new&nbsp;Date()&nbsp;+&nbsp;":&nbsp;"&nbsp;+&nbsp;msg);<BR>206&nbsp;e.printStackTrace(log);<BR>207&nbsp;}&nbsp;<BR>208&nbsp;<BR>209&nbsp;/**&nbsp;<BR>210&nbsp;*&nbsp;此内部类定义了一个连接池.它能够根据要求创建新连接,直到预定的最&nbsp;<BR>211&nbsp;*&nbsp;大连接数为止.在返回连接给客户程序之前,它能够验证连接的有效性.&nbsp;<BR>212&nbsp;*/&nbsp;<BR>213&nbsp;class&nbsp;DBConnectionPool&nbsp;{&nbsp;<BR>214&nbsp;private&nbsp;int&nbsp;checkedOut;<BR>215&nbsp;private&nbsp;Vector&nbsp;freeConnections&nbsp;=&nbsp;new&nbsp;Vector();<BR>216&nbsp;private&nbsp;int&nbsp;maxConn;<BR>217&nbsp;private&nbsp;String&nbsp;name;<BR>218&nbsp;private&nbsp;String&nbsp;password;<BR>219&nbsp;private&nbsp;String&nbsp;URL;<BR>220&nbsp;private&nbsp;String&nbsp;user;<BR>221&nbsp;<BR>222&nbsp;/**&nbsp;<BR>223&nbsp;*&nbsp;创建新的连接池&nbsp;<BR>224&nbsp;*&nbsp;<BR>225&nbsp;*&nbsp;@param&nbsp;name&nbsp;连接池名字&nbsp;<BR>226&nbsp;*&nbsp;@param&nbsp;URL&nbsp;数据库的JDBC&nbsp;URL&nbsp;<BR>227&nbsp;*&nbsp;@param&nbsp;user&nbsp;数据库帐号,或&nbsp;null&nbsp;<BR>228&nbsp;*&nbsp;@param&nbsp;password&nbsp;密码,或&nbsp;null&nbsp;<BR>229&nbsp;*&nbsp;@param&nbsp;maxConn&nbsp;此连接池允许建立的最大连接数&nbsp;<BR>230&nbsp;*/&nbsp;<BR>231&nbsp;public&nbsp;DBConnectionPool(String&nbsp;name,&nbsp;String&nbsp;URL,&nbsp;String&nbsp;user,&nbsp;String&nbsp;password,&nbsp;<BR>232&nbsp;int&nbsp;maxConn)&nbsp;{&nbsp;<BR>233&nbsp;this.name&nbsp;=&nbsp;name;<BR>234&nbsp;this.URL&nbsp;=&nbsp;URL;<BR>235&nbsp;this.user&nbsp;=&nbsp;user;<BR>236&nbsp;this.password&nbsp;=&nbsp;password;<BR>237&nbsp;this.maxConn&nbsp;=&nbsp;maxConn;<BR>238&nbsp;}&nbsp;<BR>239&nbsp;<BR>240&nbsp;/**&nbsp;<BR>241&nbsp;*&nbsp;将不再使用的连接返回给连接池&nbsp;<BR>242&nbsp;*&nbsp;<BR>243&nbsp;*&nbsp;@param&nbsp;con&nbsp;客户程序释放的连接&nbsp;<BR>244&nbsp;*/&nbsp;<BR>245&nbsp;public&nbsp;synchronized&nbsp;void&nbsp;freeConnection(Connection&nbsp;con)&nbsp;{&nbsp;<BR>246&nbsp;//&nbsp;将指定连接加入到向量末尾&nbsp;<BR>247&nbsp;freeConnections.addElement(con);<BR>248&nbsp;checkedOut--;<BR>249&nbsp;notifyAll();<BR>250&nbsp;}&nbsp;<BR>251&nbsp;<BR>252&nbsp;/**&nbsp;<BR>253&nbsp;*&nbsp;从连接池获得一个可用连接.如没有空闲的连接且当前连接数小于最大连接&nbsp;<BR>254&nbsp;*&nbsp;数限制,则创建新连接.如原来登记为可用的连接不再有效,则从向量删除之,&nbsp;<BR>255&nbsp;*&nbsp;然后递归调用自己以尝试新的可用连接.&nbsp;<BR>256&nbsp;*/&nbsp;<BR>257&nbsp;public&nbsp;synchronized&nbsp;Connection&nbsp;getConnection()&nbsp;{&nbsp;<BR>258&nbsp;Connection&nbsp;con&nbsp;=&nbsp;null;<BR>259&nbsp;if&nbsp;(freeConnections.size()&gt;<BR>0)&nbsp;{&nbsp;<BR>260&nbsp;//&nbsp;获取向量中第一个可用连接&nbsp;<BR>261&nbsp;con&nbsp;=&nbsp;(Connection)&nbsp;freeConnections.firstElement();<BR>262&nbsp;freeConnections.removeElementAt(0);<BR>263&nbsp;try&nbsp;{&nbsp;<BR>264&nbsp;if&nbsp;(con.isClosed())&nbsp;{&nbsp;<BR>265&nbsp;log("从连接池"&nbsp;+&nbsp;name+"删除一个无效连接");<BR>266&nbsp;//&nbsp;递归调用自己,尝试再次获取可用连接&nbsp;<BR>267&nbsp;con&nbsp;=&nbsp;getConnection();<BR>268&nbsp;}&nbsp;<BR>269&nbsp;}&nbsp;<BR>270&nbsp;catch&nbsp;(SQLException&nbsp;e)&nbsp;{&nbsp;<BR>271&nbsp;log("从连接池"&nbsp;+&nbsp;name+"删除一个无效连接");<BR>272&nbsp;//&nbsp;递归调用自己,尝试再次获取可用连接&nbsp;<BR>273&nbsp;con&nbsp;=&nbsp;getConnection();<BR>274&nbsp;}&nbsp;<BR>275&nbsp;}&nbsp;<BR>276&nbsp;else&nbsp;if&nbsp;(maxConn&nbsp;==&nbsp;0&nbsp;||&nbsp;checkedOut<BR>&lt;maxConn)&nbsp;{&nbsp;<BR>277&nbsp;con&nbsp;=&nbsp;newConnection();&nbsp;<BR>278&nbsp;}&nbsp;<BR>279&nbsp;if&nbsp;(con&nbsp;!=&nbsp;null)&nbsp;{&nbsp;<BR>280&nbsp;checkedOut++;&nbsp;<BR>281&nbsp;}&nbsp;<BR>282&nbsp;return&nbsp;con;&nbsp;<BR>283&nbsp;}&nbsp;<BR>284&nbsp;<BR>285&nbsp;/**&nbsp;<BR>286&nbsp;*&nbsp;从连接池获取可用连接.可以指定客户程序能够等待的最长时间&nbsp;<BR>287&nbsp;*&nbsp;参见前一个getConnection()方法.&nbsp;<BR>288&nbsp;*&nbsp;<BR>289&nbsp;*&nbsp;@param&nbsp;timeout&nbsp;以毫秒计的等待时间限制&nbsp;<BR>290&nbsp;*/&nbsp;<BR>291&nbsp;public&nbsp;synchronized&nbsp;Connection&nbsp;getConnection(long&nbsp;timeout)&nbsp;{&nbsp;<BR>292&nbsp;long&nbsp;startTime&nbsp;=&nbsp;new&nbsp;Date().getTime();&nbsp;<BR>293&nbsp;Connection&nbsp;con;&nbsp;<BR>294&nbsp;while&nbsp;((con&nbsp;=&nbsp;getConnection())&nbsp;==&nbsp;null)&nbsp;{&nbsp;<BR>295&nbsp;try&nbsp;{&nbsp;<BR>296&nbsp;wait(timeout);&nbsp;<BR>297&nbsp;}&nbsp;<BR>298&nbsp;catch&nbsp;(InterruptedException&nbsp;e)&nbsp;{}&nbsp;<BR>299&nbsp;if&nbsp;((new&nbsp;Date().getTime()&nbsp;-&nbsp;startTime)&gt;<BR>=&nbsp;timeout)&nbsp;{&nbsp;<BR>300&nbsp;//&nbsp;wait()返回的原因是超时&nbsp;<BR>301&nbsp;return&nbsp;null;<BR>302&nbsp;}&nbsp;<BR>303&nbsp;}&nbsp;<BR>304&nbsp;return&nbsp;con;<BR>305&nbsp;}&nbsp;<BR>306&nbsp;<BR>307&nbsp;/**&nbsp;<BR>308&nbsp;*&nbsp;关闭所有连接&nbsp;<BR>309&nbsp;*/&nbsp;<BR>310&nbsp;public&nbsp;synchronized&nbsp;void&nbsp;release()&nbsp;{&nbsp;<BR>311&nbsp;Enumeration&nbsp;allConnections&nbsp;=&nbsp;freeConnections.elements();<BR>312&nbsp;while&nbsp;(allConnections.hasMoreElements())&nbsp;{&nbsp;<BR>313&nbsp;Connection&nbsp;con&nbsp;=&nbsp;(Connection)&nbsp;allConnections.nextElement();<BR>314&nbsp;try&nbsp;{&nbsp;<BR>315&nbsp;con.close();<BR>316&nbsp;log("关闭连接池"&nbsp;+&nbsp;name+"中的一个连接");<BR>317&nbsp;}&nbsp;<BR>318&nbsp;catch&nbsp;(SQLException&nbsp;e)&nbsp;{&nbsp;<BR>319&nbsp;log(e,&nbsp;"无法关闭连接池"&nbsp;+&nbsp;name+"中的连接");<BR>320&nbsp;}&nbsp;<BR>321&nbsp;}&nbsp;<BR>322&nbsp;freeConnections.removeAllElements();<BR>323&nbsp;}&nbsp;<BR>324&nbsp;<BR>325&nbsp;/**&nbsp;<BR>326&nbsp;*&nbsp;创建新的连接&nbsp;<BR>327&nbsp;*/&nbsp;<BR>328&nbsp;private&nbsp;Connection&nbsp;newConnection()&nbsp;{&nbsp;<BR>329&nbsp;Connection&nbsp;con&nbsp;=&nbsp;null;<BR>330&nbsp;try&nbsp;{&nbsp;<BR>331&nbsp;if&nbsp;(user&nbsp;==&nbsp;null)&nbsp;{&nbsp;<BR>332&nbsp;con&nbsp;=&nbsp;DriverManager.getConnection(URL);<BR>333&nbsp;}&nbsp;<BR>334&nbsp;else&nbsp;{&nbsp;<BR>335&nbsp;con&nbsp;=&nbsp;DriverManager.getConnection(URL,&nbsp;user,&nbsp;password);<BR>336&nbsp;}&nbsp;<BR>337&nbsp;log("连接池"&nbsp;+&nbsp;name+"创建一个新的连接");<BR>338&nbsp;}&nbsp;<BR>339&nbsp;catch&nbsp;(SQLException&nbsp;e)&nbsp;{&nbsp;<BR>340&nbsp;log(e,&nbsp;"无法创建下列URL的连接:&nbsp;"&nbsp;+&nbsp;URL);<BR>341&nbsp;return&nbsp;null;<BR>342&nbsp;}&nbsp;<BR>343&nbsp;return&nbsp;con;<BR>344&nbsp;}&nbsp;<BR>345&nbsp;}&nbsp;<BR>346&nbsp;}&nbsp;<BR><BR><BR>三、类DBConnectionPool说明&nbsp;<BR><BR>该类在209至345行实现，它表示指向某个数据库的连接池。数据库由JDBC&nbsp;URL标识。一个JDBC&nbsp;URL由三部分组成：协议标识（总是jdbc），驱动程序标识（如&nbsp;odbc、idb、oracle等），数据库标识（其格式依赖于驱动程序）。例如，jdbc:odbc:demo，即是一个指向demo数据库的JDBC&nbsp;URL，而且访问该数据库要使用JDBC-ODBC驱动程序。每个连接池都有一个供客户程序使用的名字以及可选的用户帐号、密码、最大连接数限制。如果Web应用程序所支持的某些数据库操作可以被所有用户执行，而其它一些操作应由特别许可的用户执行，则可以为两类操作分别定义连接池，两个连接池使用相同的JDBC&nbsp;URL，但使用不同的帐号和密码。&nbsp;<BR>类DBConnectionPool的建构函数需要上述所有数据作为其参数。如222至238行所示，这些数据被保存为它的实例变量：&nbsp;<BR>如252至283行、285至305行所示，&nbsp;客户程序可以使用DBConnectionPool类提供的两个方法获取可用连接。两者的共同之处在于：如连接池中存在可用连接，则直接返回，否则创建新的连接并返回。如果没有可用连接且已有连接总数等于最大限制数，第一个方法将直接返回null，而第二个方法将等待直到有可用连接为止。&nbsp;<BR>所有的可用连接对象均登记在名为freeConnections的向量（Vector）中。如果向量中有多于一个的连接，getConnection()总是选取第一个。同时，由于新的可用连接总是从尾部加入向量，从而使得数据库连接由于长时间闲置而被关闭的风险减低到最小程度。&nbsp;<BR>第一个getConnection()在返回可用连接给客户程序之前，调用了isClosed()方法验证连接仍旧有效。如果该连接被关闭或触发异常，getConnection()递归地调用自己以尝试获取另外的可用连接。如果在向量freeConnections中不存在任何可用连接，getConnection()方法检查是否已经指定最大连接数限制。如已经指定，则检查当前连接数是否已经到达极限。此处maxConn为0表示没有限制。如果没有指定最大连接数限制或当前连接数小于该值，该方法尝试创建新的连接。如创建成功，则增加已使用连接的计数并返回，否则返回空值。&nbsp;<BR>如325至345行所示，创建新连接由newConnection()方法实现。创建过程与是否已经指定数据库帐号、密码有关。&nbsp;<BR>JDBC的DriverManager类提供多个getConnection()方法，这些方法要用到JDBC&nbsp;URL与其它一些参数，如用户帐号和密码等。DriverManager将使用指定的JDBC&nbsp;URL确定适合于目标数据库的驱动程序及建立连接。&nbsp;<BR>在285至305行实现的第二个getConnection()方法需要一个以毫秒为单位的时间参数，该参数表示客户程序能够等待的最长时间。建立连接的具体操作仍旧由第一个getConnection()方法实现。&nbsp;<BR>该方法执行时先将startTime初始化为当前时间。在while循环中尝试获得一个连接。如果失败，则以给定的时间值为参数调用wait()。wait()的返回可能是由于其它线程调用notify()或notifyAll()，也可能是由于预定时间已到。为找出wait()返回的真正原因，程序用当前时间减开始时间（startTime），如差值大于预定时间则返回空值，否则再次调用getConnection()。&nbsp;<BR>把空闲的连接登记到连接池由240至250行的freeConnection()方法实现，它的参数为返回给连接池的连接对象。该对象被加入到freeConnections向量的末尾，然后减少已使用连接计数。调用notifyAll()是为了通知其它正在等待可用连接的线程。&nbsp;<BR>许多Servlet引擎为实现安全关闭提供多种方法。数据库连接池需要知道该事件以保证所有连接能够正常关闭。DBConnectionManager类负协调整个关闭过程，但关闭连接池中所有连接的任务则由DBConnectionPool类负责。在307至323行实现的release()方法供DBConnectionManager调用。该方法遍历freeConnections向量并关闭所有连接，然后从向量中删除这些连接。&nbsp;<BR><BR><BR>四、类DBConnectionManager&nbsp;说明&nbsp;<BR><BR>该类只能创建一个实例，其它对象能够调用其静态方法（也称为类方法）获得该唯一实例的引用。如031至036行所示，DBConnectionManager类的建构函数是私有的，这是为了避免其它对象创建该类的实例。&nbsp;<BR>DBConnectionManager类的客户程序可以调用getInstance()方法获得对该类唯一实例的引用。如018至029行所示，类的唯一实例在getInstance()方法第一次被调用期间创建，此后其引用就一直保存在静态变量instance中。每次调用getInstance()都增加一个DBConnectionManager的客户程序计数。即，该计数代表引用DBConnectionManager唯一实例的客户程序总数，它将被用于控制连接池的关闭操作。&nbsp;<BR>该类实例的初始化工作由146至168行之间的私有方法init()完成。其中&nbsp;getResourceAsStream()方法用于定位并打开外部文件。外部文件的定位方法依赖于类装载器的实现。标准的本地类装载器查找操作总是开始于类文件所在路径，也能够搜索CLASSPATH中声明的路径。db.properties是一个属性文件，它包含定义连接池的键-值对。可供定义的公用属性如下：&nbsp;<BR><BR>drivers&nbsp;以空格分隔的JDBC驱动程序类列表&nbsp;<BR>logfile&nbsp;日志文件的绝对路径&nbsp;<BR><BR>其它的属性和特定连接池相关，其属性名字前应加上连接池名字：<BR>&lt;poolname&gt;<BR>.url&nbsp;数据库的&nbsp;JDBC&nbsp;URL<BR>&lt;poolname&gt;<BR>.maxconn&nbsp;允许建立的最大连接数，0表示没有限制<BR>&lt;poolname&gt;<BR>.user&nbsp;用于该连接池的数据库帐号<BR>&lt;poolname&gt;<BR>.password&nbsp;相应的密码&nbsp;<BR><BR>其中url属性是必需的，而其它属性则是可选的。数据库帐号和密码必须合法。用于Windows平台的db.properties文件示例如下：&nbsp;<BR><BR>drivers=sun.jdbc.odbc.JdbcOdbcDriver&nbsp;jdbc.idbDriver&nbsp;<BR>logfile=D:\\user\\src\\java\\DBConnectionManager\\log.txt&nbsp;<BR><BR>idb.url=jdbc:idb:c:\\local\\javawebserver1.1\\db\\db.prp&nbsp;<BR>idb.maxconn=2&nbsp;<BR><BR>access.url=jdbc:odbc:demo&nbsp;<BR>access.user=demo&nbsp;<BR>access.password=demopw&nbsp;<BR><BR>注意在Windows路径中的反斜杠必须输入2个，这是由于属性文件中的反斜杠同时也是一个转义字符。&nbsp;<BR>init()方法在创建属性对象并读取db.properties文件之后，就开始检查logfile属性。如果属性文件中没有指定日志文件，则默认为当前目录下的DBConnectionManager.log文件。如日志文件无法使用，则向System.err输出日志记录。&nbsp;<BR>装载和注册所有在drivers属性中指定的JDBC驱动程序由170至192行之间的loadDrivers()方法实现。该方法先用StringTokenizer将drivers属性值分割为对应于驱动程序名称的字符串，然后依次装载这些类并创建其实例，最后在&nbsp;DriverManager中注册该实例并把它加入到一个私有的向量drivers。向量drivers将用于关闭服务时从DriverManager取消所有JDBC&nbsp;驱动程序的注册。&nbsp;<BR>init()方法的最后一个任务是调用私有方法createPools()创建连接池对象。如109至142行所示，createPools()方法先创建所有属性名字的枚举对象（即Enumeration对象，该对象可以想象为一个元素系列，逐次调用其nextElement()方法将顺序返回各元素），然后在其中搜索名字以“.url”结尾的属性。对于每一个符合条件的属性，先提取其连接池名字部分，进而读取所有属于该连接池的属性，最后创建连接池对象并把它保存在实例变量pools中。散列表（Hashtable类&nbsp;）pools实现连接池名字到连接池对象之间的映射，此处以连接池名字为键，连接池对象为值。&nbsp;<BR>为便于客户程序从指定连接池获得可用连接或将连接返回给连接池，类DBConnectionManager提供了方法getConnection()和freeConnection()。所有这些方法都要求在参数中指定连接池名字，具体的连接获取或返回操作则调用对应的连接池对象完成。它们的实现分别在051至064行、066至080行、038至049行。&nbsp;<BR>如082至107行所示，为实现连接池的安全关闭，DBConnectionManager提供了方法release()。在上面我们已经提到，所有DBConnectionManager的客户程序都应该调用静态方法getInstance()以获得该管理器的引用，此调用将增加客户程序计数。客户程序在关闭时调用release()可以递减该计数。当最后一个客户程序调用release()，递减后的引用计数为0，就可以调用各个连接池的release()方法关闭所有连接了。管理类release()方法最后的任务是撤销所有JDBC驱动程序的注册。&nbsp;<BR><BR><BR>五、Servlet使用连接池示例&nbsp;<BR><BR>Servlet&nbsp;API所定义的Servlet生命周期类如：&nbsp;<BR><BR>1)&nbsp;创建并初始化Servlet（init()方法）。&nbsp;<BR>2)&nbsp;响应客户程序的服务请求（service()方法）。&nbsp;<BR>3)&nbsp;Servlet终止运行，释放所有资源（destroy()方法）。&nbsp;<BR><BR>本例演示连接池应用，上述关键步骤中的相关操作为：&nbsp;<BR><BR>1)&nbsp;在init()，用实例变量connMgr&nbsp;保存调用DBConnectionManager.getInstance()所返回的引用。&nbsp;<BR>2)&nbsp;在service()，调用getConnection()，执行数据库操作，用freeConnection()将连接返回给连接池。&nbsp;<BR>3)&nbsp;在destroy()，调用release()关闭所有连接，释放所有资源。&nbsp;<BR><BR>示例程序清单如下：&nbsp;<BR><BR>import&nbsp;java.io.*;<BR>import&nbsp;java.sql.*;<BR>import&nbsp;javax.servlet.*;<BR>import&nbsp;javax.servlet.http.*;<BR>public&nbsp;class&nbsp;TestServlet&nbsp;extends&nbsp;HttpServlet&nbsp;{&nbsp;<BR>private&nbsp;DBConnectionManager&nbsp;connMgr;<BR><BR>public&nbsp;void&nbsp;init(ServletConfig&nbsp;conf)&nbsp;throws&nbsp;ServletException&nbsp;{&nbsp;<BR>super.init(conf);<BR>connMgr&nbsp;=&nbsp;DBConnectionManager.getInstance();<BR>}&nbsp;<BR><BR>public&nbsp;void&nbsp;service(HttpServletRequest&nbsp;req,&nbsp;HttpServletResponse&nbsp;res)&nbsp;<BR>throws&nbsp;IOException&nbsp;{&nbsp;<BR><BR>res.setContentType("text/html");<BR>PrintWriter&nbsp;out&nbsp;=&nbsp;res.getWriter();<BR>Connection&nbsp;con&nbsp;=&nbsp;connMgr.getConnection("idb");<BR>if&nbsp;(con&nbsp;==&nbsp;null)&nbsp;{&nbsp;<BR>out.println("不能获取数据库连接.");<BR>return;<BR>}&nbsp;<BR>ResultSet&nbsp;rs&nbsp;=&nbsp;null;<BR>ResultSetMetaData&nbsp;md&nbsp;=&nbsp;null;<BR>Statement&nbsp;stmt&nbsp;=&nbsp;null;<BR>try&nbsp;{&nbsp;<BR>stmt&nbsp;=&nbsp;con.createStatement();<BR>rs&nbsp;=&nbsp;stmt.executeQuery("SELECT&nbsp;*&nbsp;FROM&nbsp;EMPLOYEE");<BR>md&nbsp;=&nbsp;rs.getMetaData();<BR>out.println("<BR>&lt;H1&gt;<BR>职工数据<BR>&lt;/H1&gt;<BR>");<BR>while&nbsp;(rs.next())&nbsp;{&nbsp;<BR>out.println("<BR>&lt;BR&gt;<BR>");<BR>for&nbsp;(int&nbsp;i&nbsp;=&nbsp;1;i"<BR>&lt;md.getColumnCount();i++)&nbsp;{&nbsp;<BR>out.print(rs.getString(i)&nbsp;+&nbsp;",&nbsp;");<BR>}&nbsp;<BR>}&nbsp;<BR>stmt.close();<BR>rs.close();<BR>}&nbsp;<BR>catch&nbsp;(SQLException&nbsp;e)&nbsp;{&nbsp;<BR>e.printStackTrace(out);<BR>}&nbsp;<BR>connMgr.freeConnection("idb",&nbsp;con);<BR>}&nbsp;<BR><BR>public&nbsp;void&nbsp;destroy()&nbsp;{&nbsp;<BR>connMgr.release();<BR>super.destroy();<BR>}&nbsp;<BR>}<BR><BR><BR>不行，这不是我要找的，我要再从<A HREF="/searchInternet.asp?query=用连接池提高Servlet访问数据库的效率" target=_blank><FONT color=red>从互联网上搜索与此相关的内容</FONT></A><BR><img src ="http://www.blogjava.net/aiyoyoyo/aggbug/31225.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/aiyoyoyo/" target="_blank">aiyoyoyo</a> 2006-02-17 16:43 <a href="http://www.blogjava.net/aiyoyoyo/articles/31225.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java解决国际化问题（ResourceBundle）</title><link>http://www.blogjava.net/aiyoyoyo/articles/31215.html</link><dc:creator>aiyoyoyo</dc:creator><author>aiyoyoyo</author><pubDate>Fri, 17 Feb 2006 08:12:00 GMT</pubDate><guid>http://www.blogjava.net/aiyoyoyo/articles/31215.html</guid><wfw:comment>http://www.blogjava.net/aiyoyoyo/comments/31215.html</wfw:comment><comments>http://www.blogjava.net/aiyoyoyo/articles/31215.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/aiyoyoyo/comments/commentRss/31215.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/aiyoyoyo/services/trackbacks/31215.html</trackback:ping><description><![CDATA[<H3 class=title>&nbsp;&nbsp;&nbsp; 在用Java解决国际化问题的过程中，可能利用到的主要的类都是由java.util包提供的。该类包中相关的类有Locale、ResourceBundle、ListResourceBundle、PropertyResourceBundle等。<BR>&nbsp;&nbsp;&nbsp; Locale：该类包含对主要地理区域的地域化特征的封装。其特定对象表示某一特定的地理、政治或文化区域。通过设定Locale，我们可以为特定的国家或地区提供符合当地文化习惯的字体、符号、图标和表达格式。例如，我们可以通过获得特定Locale下的Calendar类的实例，显示符合特定表达格式的日期。<BR>&nbsp;&nbsp;&nbsp; ResourceBundle：该类是一个抽象类，需要通过静态方法ResourceBundle.getBundle()指定具体实现类或属性文件的基本名称。基本名称会协同指定的或默认的Locale类，决定具体调用的类或属性文件的唯一名称。例如：指定基本类或属性文件名称为TestBundle，而指定的Locale是CHINESE，那么最适合匹配的类名称为TestBundle_zh_CN.class，而最佳匹配属性文件名称为TestBundle_zh_CN.properties。按照Java Doc和相关文档的要求，如果该类或属性文件没有找到，系统会查找近似匹配（主文件名依次为TestBundle_zh和TestBundle的类或属性文件）。该类提供的getKeys()方法用于获得所有成员的键名，并提供handleGetObject方法获得指定键的对应元素。<BR>&nbsp;&nbsp;&nbsp; ListResourceBundle：该类继承ResourceBundle类，主要是增加了一些便于操作的成分，但还是抽象类。如果希望使用类的方式实现具体的ResourceBundle，一般情况下最好继承这个类。<BR>&nbsp;&nbsp;&nbsp; PropertyResourceBundle：该类也继承ResourceBundle类，可以实例化。该类的行为特征如同java.util.properties类，可以从输入流中获得具体属性对。<BR>&nbsp;&nbsp;&nbsp; 使用PropertyResourceBundle类获得当地版本的国际化信息，部分代码如下……<BR>&nbsp;&nbsp;&nbsp; public static final String BASE_PROP_FILE = “DISP”;<BR>　　public static final String SUFFIX = “.properties”;<BR>　　locale = Locale.getDefault();<BR>　　String propFile = BASE_PROP_FILE ＋ “_” ＋ locale.toString()＋ SUFFIX;<BR>　　ResourceBundle rb;<BR>　　try {<BR>　　　File file = new File(propFile);<BR>　　　if (file.exists()) {<BR>&nbsp; 　　　is = new FileInputStream(file);<BR>&nbsp;&nbsp; 　　 rb = new PropertyResourceBundle(is);<BR>&nbsp;&nbsp; 　　 if (rb == null) System.out.println(“No Resource”);<BR>　　　}<BR>　　} catch (IOException ioe) {<BR>　　　System.out.println(“Error open file named ” ＋ propFile);<BR>　　}<BR>　　Enumeration e = rb.getKeys();<BR>　　while (e.hasMoreElements()){<BR>　　　key = (String)e.nextElement();<BR>　　　value = (String)rb.handleGetObject(key); <BR>　　　System.out.println(“KEY: ” ＋ key ＋“ Value: ” ＋ value);<BR>　　}<BR>　　……<BR>　　DISP_zh_TW.properties文件的具体内容如下：<BR>　　Key1=可以<BR>　　Key2=撤销<BR>&nbsp;&nbsp;&nbsp; 等号后面是利用native2ascii程序转化后的繁体汉字，如果不进行转化，系统可能显示乱码。<BR>&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; 处理提示和帮助<BR>&nbsp;&nbsp;&nbsp; 对于提示语言和帮助文件部分，可以把语言映射放在属性文件或者ListResourceBundle类的子类中。下面程序是一个Servlet，它通过接受客户端的选择，把特定语言和字符版本的信息返回到客户端。　　public class ProcessServlet extends HttpServlet <BR>　　{ //默认语言为中文<BR>　　　public static final String DEFAULT_LANGUAGE = “zh”; <BR>　　　//默认字符集为简体中文<BR>　　　public static final String DEFAULT_COUNTRY = “CN”; <BR>　　　public void service(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException {<BR>　　 HttpSession session = req.getSession(true);<BR>　　 // 从客户端收到的指定语言和字符的参数应当与Sun公司相关规定一致<BR>　　 String lang = req.getParameter(“language”);<BR>　　 String country = req.getParameter(“country”);<BR>　　 if (lang == null) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //如果没有收到参数，就试图从Session里获得<BR>&nbsp; 　　 lang = (String) session.getAttribute(“language”);<BR>&nbsp; 　　 country = (String) session.getAttribute(“country”);<BR>　　 } else {<BR>&nbsp; 　　 session.setAttribute(“language”, lang);<BR>&nbsp; 　　 session.setAttribute(“country”, country);<BR>　　 }<BR>　　 if (lang == null){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //如果无法从上述手段得到语言和字符信息，就使用默认值<BR>&nbsp; 　　 lang = DEFAULT_LANGUAGE;<BR>&nbsp; 　　 country = DEFAULT_COUNTRY<BR>&nbsp; 　　 session.setAttribute(“language”, lang);<BR>　 　　session.setAttribute(“country”, country);<BR>　　 }<BR>　　 Locale locale = null;<BR>　　 ResourceBundle bundle = null;<BR>　　 try {<BR>&nbsp; 　　 locale = new Locale(lang, country);<BR>&nbsp; 　 } catch (Exception e) {<BR>&nbsp;&nbsp;&nbsp; 　 System.out.println(“No locale with” ＋ country ＋ “_” ＋ lang);<BR>&nbsp; 　　 locale = Locale.getDefault();<BR>&nbsp; 　 }<BR>&nbsp; 　 try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bundle = ResourceBundle.getBundle(“DisplayList”, locale);<BR>　　 } catch( MissingResourceException e) {<BR>&nbsp; 　　 System.out.println( “No resources available for locale ” ＋ locale);<BR>&nbsp; 　　 bundle = ResourceBundle.getBundle(“DisplayList”, Locale.US);<BR>　　 }<BR>　　 res.setContentType(“text/html”);<BR>　　 PrintWriter out = res.getWriter();<BR>　　 out.println(“&amp;lt;html&amp;gt;”);<BR>　　 out.println(“&amp;lt;head&amp;gt;”);<BR>　　 String title = bundle.getString(“title”);<BR>&nbsp; 　 String welcome =bundle.getString(“welcome”);<BR>　　 String notice = bundle.getString(“notice”);<BR>　　 out.println(“&amp;lt;title&amp;gt;”＋ title ＋“&amp;lt;/title&amp;gt;”);<BR>　　 out.println(“&amp;lt;/head&amp;gt;”);<BR>　　 out.println(“&amp;lt;body bgcolor=”white“&amp;gt;”);<BR>　　 out.println(“&amp;lt;h3&amp;gt;” ＋ welcome ＋ “&amp;lt;/h3&amp;gt;”);<BR>　　 out.println(“&amp;lt;br&amp;gt;”);<BR>　　 out.println(“&amp;lt;b&amp;gt;” ＋ notice ＋“&amp;lt;/b&amp;gt;”);<BR>　　 out.println(“&amp;lt;/body&amp;gt;”);<BR>　　 out.println(“&amp;lt;/html&amp;gt;”);<BR>　 }<BR>&nbsp; }<BR>上述Servlet使用的属性文件（DisplayList_zh_CN.properties）内容如下：<BR>title=中文版<BR>welcome=这是简体中文版面<BR>notice=简体中文测试成功<BR>注意：该文件直接采用了中文，而不是经过转化的Unicode编码，这是由于大多数Web服务器不需要上述转化。<BR>&nbsp;&nbsp;&nbsp; 在实际使用中，如果Web服务器支持Servlet 2.3规范（如jakarta－tomcate 4.0），那么上面提到的Servlet应当稍加改变，以作为其他Servlet的处理器使用。另外，如果把ResourceBundle的特定版本存放在无状态会话Bean中，就可以在一定程度上提高程序效率。<BR>&nbsp;&nbsp;&nbsp; 对于显示字符出现乱码的问题，如果是通过属性文件实现国际化解决方案，那么可能是直接在属性文件中写入了非标准ASCII文字。解决方法是利用JDK提供的工具native2ascii.exe扫描所有属性文件，用扫描结果覆盖原有文件内容。如果我们是利用类文件实现转换方案，那么需要重新编译相关类文件，并在编译时指定编码集。例如，编译使用国标码的类文件，采用的编译命令如下：<BR>javac －encoding GB2312 your_java_file</H3><img src ="http://www.blogjava.net/aiyoyoyo/aggbug/31215.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/aiyoyoyo/" target="_blank">aiyoyoyo</a> 2006-02-17 16:12 <a href="http://www.blogjava.net/aiyoyoyo/articles/31215.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSP乱码解决（过虑器EncodingFilter）</title><link>http://www.blogjava.net/aiyoyoyo/articles/31211.html</link><dc:creator>aiyoyoyo</dc:creator><author>aiyoyoyo</author><pubDate>Fri, 17 Feb 2006 08:06:00 GMT</pubDate><guid>http://www.blogjava.net/aiyoyoyo/articles/31211.html</guid><wfw:comment>http://www.blogjava.net/aiyoyoyo/comments/31211.html</wfw:comment><comments>http://www.blogjava.net/aiyoyoyo/articles/31211.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/aiyoyoyo/comments/commentRss/31211.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/aiyoyoyo/services/trackbacks/31211.html</trackback:ping><description><![CDATA[<P>做JSP程序时页面传的文字经常是乱码，如何解决呢？</P>
<P>一种方法是把tomcat中所有的&lt;Connector&gt;标签的URIEncoding属性进行设置,如: &lt;Connector port="8000" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" redirectPort="8443" acceptCount="100" debug="0" connectionTimeout="20000" disableUploadTimeout="true" URIEncoding="GBK" /&gt;</P>
<P>而另一种方法就是写过滤器</P>
<P>import javax.servlet.*;<BR>import javax.servlet.http.HttpServletRequest;<BR>import java.io.IOException;</P>
<P>public class EncodingFilter implements Filter {<BR>&nbsp;&nbsp;&nbsp; FilterConfig config = null;<BR>&nbsp;&nbsp;&nbsp; // default to GBK<BR>&nbsp;&nbsp;&nbsp; private String targetEncoding = "GBK";</P>
<P>&nbsp;&nbsp;&nbsp; public void init(FilterConfig config) throws ServletException {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.config = config;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.targetEncoding = config.getInitParameter("encoding");<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; public void destroy() {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; config = null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; targetEncoding = null;<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; public void doFilter(ServletRequest srequest, ServletResponse sresponse,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FilterChain chain) throws IOException, ServletException {</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HttpServletRequest request = (HttpServletRequest)srequest;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; request.setCharacterEncoding(targetEncoding);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; chain.doFilter(srequest, sresponse);<BR>&nbsp;&nbsp;&nbsp; }<BR>}</P>
<P>配置：在web.xml中添加<BR>&nbsp;&nbsp;&nbsp; &lt;filter&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;filter-name&gt;encodingFilter&lt;/filter-name&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;filter-class&gt;xx.xx.xx.EncodingFilter&lt;/filter-class&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;init-param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-name&gt;encoding&lt;/param-name&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-value&gt;Shift_JIS&lt;/param-value&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/init-param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;init-param&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-name&gt;useragents&lt;/param-name&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-value&gt;Mac&lt;/param-value&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/init-param&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;/filter&gt;<BR><BR>&nbsp;&nbsp;&nbsp; &lt;filter-mapping&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;filter-name&gt;encodingFilter&lt;/filter-name&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;url-pattern&gt;/*&lt;/url-pattern&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;/filter-mapping&gt;<BR><BR>至于来自何处，忘记了。嘿嘿。。。</P><img src ="http://www.blogjava.net/aiyoyoyo/aggbug/31211.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/aiyoyoyo/" target="_blank">aiyoyoyo</a> 2006-02-17 16:06 <a href="http://www.blogjava.net/aiyoyoyo/articles/31211.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>