﻿<?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/libin2722/category/25732.html</link><description>虚其心，可解天下之问；专其心，可治天下之学；静其心，可悟天下之理；恒其心，可成天下之业。</description><language>zh-cn</language><lastBuildDate>Sun, 02 Aug 2009 02:04:13 GMT</lastBuildDate><pubDate>Sun, 02 Aug 2009 02:04:13 GMT</pubDate><ttl>60</ttl><item><title>利用开源组件制作验证码 Captcha</title><link>http://www.blogjava.net/libin2722/articles/288850.html</link><dc:creator>礼物</dc:creator><author>礼物</author><pubDate>Wed, 29 Jul 2009 02:37:00 GMT</pubDate><guid>http://www.blogjava.net/libin2722/articles/288850.html</guid><wfw:comment>http://www.blogjava.net/libin2722/comments/288850.html</wfw:comment><comments>http://www.blogjava.net/libin2722/articles/288850.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/libin2722/comments/commentRss/288850.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/libin2722/services/trackbacks/288850.html</trackback:ping><description><![CDATA[
		<div class="blog_content">
				<p>jsp验证码制作</p>
				<p> </p>
				<p>　　介绍两个功能强大的开源制作验证码组件SimpleCaptcha，JCAPTCHA。</p>
				<p> </p>
				<p>　　一、SimpleCaptcha搜狐邮箱注册时就使用了该组件，主页:<br />  <a href="http://simplecaptcha.sourceforge.net/index.html">http://simplecaptcha.sourceforge.net/index.html</a></p>
				<p> </p>
				<p>
						<img alt="example" />
				</p>
				<p>
						<br /> 1.配置<br />  将下载的jar文件放置工程的lib目录下，打开工程的web.xml文件加上相应的配置<br /> &lt;<span class="hilite4">servlet</span>&gt;<br />  &lt;<span class="hilite4">servlet</span>-name&gt;<span class="hilite3">Captcha</span>&lt;/<span class="hilite4">servlet</span>-name&gt;<br />  &lt;<span class="hilite4">servlet</span>-class&gt;<span class="hilite2">nl</span>.<span class="hilite3">captcha</span>.<span class="hilite4">servlet</span>.CaptchaServlet&lt;/<span class="hilite4">servlet</span>-class&gt;<br />  &lt;!--边框显示参数--&gt;<br />  &lt;init-param&gt;<br />   &lt;param-name&gt;cap.border&lt;/param-name&gt;<br />   &lt;param-value&gt;yes&lt;/param-value&gt;<br />  &lt;/init-param&gt;</p>
				<p>  &lt;!-- 设置图片边框色 --&gt;<br />  &lt;init-param&gt;<br />   &lt;param-name&gt;cap.border.c&lt;/param-name&gt;<br />   &lt;param-value&gt;green&lt;/param-value&gt;<br />  &lt;/init-param&gt;</p>
				<p>  &lt;!-- 边框粗细--&gt;<br />  &lt;init-param&gt;<br />   &lt;param-name&gt;cap.border.th&lt;/param-name&gt;<br />   &lt;param-value&gt;1&lt;/param-value&gt;<br />  &lt;/init-param&gt;</p>
				<p>  &lt;!-- the image producer. Currently only one--&gt;<br />  &lt;init-param&gt;<br />   &lt;param-name&gt;cap.cap.producer&lt;/param-name&gt;<br />   &lt;param-value&gt;<br />    <span class="hilite2">nl</span>.<span class="hilite3">captcha</span>.obscurity.imp.DefaultCaptchaIml<br />   &lt;/param-value&gt;<br />  &lt;/init-param&gt;</p>
				<p>  &lt;!-- 设置验证码的内容 --&gt;<br />  &lt;init-param&gt;<br />   &lt;param-name&gt;cap.text.producer&lt;/param-name&gt;<br />   &lt;!--&lt;param-value&gt;Default&lt;/param-value&gt;--&gt;<br />   &lt;!-- 此处是我自定义的一个显示中文的类 --&gt;<br />   &lt;param-value&gt;org.ChineseTextProducer&lt;/param-value&gt;<br />  &lt;/init-param&gt;</p>
				<p>  &lt;!-- 此处可不定义，可在自定义类中定义所有的要显示的内容　--&gt;<br />  &lt;init-param&gt;<br />   &lt;param-name&gt;cap.char.arr&lt;/param-name&gt;<br />   &lt;param-value&gt;<br />    2,3,4,6,7,8,9,a,b,c,d,e,f,g,h,j,k,l,m,n,o,p,q,r,s,t,u,v,x,y,z<br />   &lt;/param-value&gt;<br />  &lt;/init-param&gt;</p>
				<p>  &lt;!-- 设置图片显示内容长度 --&gt;<br />  &lt;init-param&gt;<br />   &lt;param-name&gt;cap.char.arr.l&lt;/param-name&gt;<br />   &lt;param-value&gt;4&lt;/param-value&gt;<br />  &lt;/init-param&gt;</p>
				<p>  &lt;init-param&gt;<br />   &lt;param-name&gt;cap.font.arr&lt;/param-name&gt;<br />   &lt;!-- 如果使用中文时设置成中文的字体 --&gt;<br />   &lt;param-value&gt;<br />    Arial,Helvetica,Courier,TimesRoman,宋体,黑体<br />   &lt;/param-value&gt;<br />  &lt;/init-param&gt;</p>
				<p>  &lt;!-- 设置字体大小 --&gt;<br />  &lt;init-param&gt;<br />   &lt;param-name&gt;cap.font.size&lt;/param-name&gt;<br />   &lt;param-value&gt;30&lt;/param-value&gt;<br />  &lt;/init-param&gt;</p>
				<p>  &lt;!-- 设置图片字体色 --&gt;<br />  &lt;init-param&gt;<br />   &lt;param-name&gt;cap.font.color&lt;/param-name&gt;<br />   &lt;param-value&gt;white&lt;/param-value&gt;<br />  &lt;/init-param&gt;<br />  <br />  &lt;!-- 扭曲; 曲解; 变形 begin --&gt;<br />  &lt;!-- 图片效果1<br />  &lt;init-param&gt;<br />   &lt;param-name&gt;cap.obscurificator&lt;/param-name&gt;<br />   以下任选一<br />   &lt;param-value&gt;<span class="hilite2">nl</span>.<span class="hilite3">captcha</span>.obscurity.imp.ShadowGimpyImp&lt;/param-value&gt;<br />   &lt;param-value&gt;<span class="hilite2">nl</span>.<span class="hilite3">captcha</span>.obscurity.imp.WaterRiple&lt;/param-value&gt;<br />   &lt;param-value&gt;<span class="hilite2">nl</span>.<span class="hilite3">captcha</span>.sandbox.TestGimpyImp&lt;/param-value&gt;<br />  &lt;/init-param&gt;<br />  --&gt;<br />  &lt;init-param&gt;<br />   &lt;param-name&gt;cap.obscurificator&lt;/param-name&gt;<br />   &lt;param-value&gt;org.FishEyeGimpyImp&lt;/param-value&gt;<br />  &lt;/init-param&gt;</p>
				<p>  &lt;init-param&gt;<br />   &lt;param-name&gt;cap.border&lt;/param-name&gt;<br />   &lt;param-value&gt;no&lt;/param-value&gt;<br />  &lt;/init-param&gt;</p>
				<p>  &lt;init-param&gt;<br />   &lt;param-name&gt;cap.char.arr.l&lt;/param-name&gt;<br />   &lt;param-value&gt;6&lt;/param-value&gt;<br />  &lt;/init-param&gt;</p>
				<p>  &lt;init-param&gt;<br />   &lt;param-name&gt;cap.background.c.to&lt;/param-name&gt;<br />   &lt;param-value&gt;white&lt;/param-value&gt;<br />  &lt;/init-param&gt;<br />  <br />  &lt;init-param&gt;<br />   &lt;param-name&gt;cap.background.c.from&lt;/param-name&gt;<br />   &lt;param-value&gt;white&lt;/param-value&gt;<br />  &lt;/init-param&gt;<br />  &lt;!--扭曲; 曲解; 变形 end 不想要这种效果可注释以上代码--&gt;</p>
				<p>
						<br />  &lt;init-param&gt;<br />   &lt;param-name&gt;cap.distortionImp&lt;/param-name&gt;<br />   &lt;param-value /&gt;<br />  &lt;/init-param&gt;</p>
				<p>  &lt;init-param&gt;<br />   &lt;param-name&gt;cap.backgroundImp&lt;/param-name&gt;<br />   &lt;param-value /&gt;<br />  &lt;/init-param&gt;</p>
				<p>  &lt;!-- 此处色为渐变的色 --&gt;<br />  &lt;init-param&gt;<br />   &lt;param-name&gt;cap.background.c.to&lt;/param-name&gt;<br />   &lt;param-value&gt;black&lt;/param-value&gt;<br />  &lt;/init-param&gt;</p>
				<p>  &lt;!-- 图片左边色 --&gt;<br />  &lt;init-param&gt;<br />   &lt;param-name&gt;cap.background.c.from&lt;/param-name&gt;<br />   &lt;param-value&gt;black&lt;/param-value&gt;<br />  &lt;/init-param&gt;</p>
				<p>  &lt;!--干扰线实现类--&gt;<br />  &lt;init-param&gt;<br />   &lt;param-name&gt;cap.noiseImp&lt;/param-name&gt;<br />   &lt;param-value&gt;<span class="hilite2">nl</span>.<span class="hilite3">captcha</span>.obscurity.imp.DefaultNoiseImp&lt;/param-value&gt;<br />  &lt;/init-param&gt;</p>
				<p>  &lt;!-- 干扰线色<br />  &lt;init-param&gt;<br />   &lt;param-name&gt;cap.noise.c&lt;/param-name&gt;<br />   &lt;param-value&gt;255,245,219&lt;/param-value&gt;<br />  &lt;/init-param&gt;<br />   --&gt;<br /> &lt;/<span class="hilite4">servlet</span>&gt;<br /> &lt;<span class="hilite4">servlet</span>-mapping&gt;<br />  &lt;<span class="hilite4">servlet</span>-name&gt;<span class="hilite3">Captcha</span>&lt;/<span class="hilite4">servlet</span>-name&gt;<br />  &lt;url-pattern&gt;/<span class="hilite3">Captcha</span>.jpg&lt;/url-pattern&gt;<br /> &lt;/<span class="hilite4">servlet</span>-mapping&gt;<br />  以上配置可根据喜好设置。</p>
				<p> </p>
				<p> 2、调用显示</p>
				<p> 在要显示验证码的页面中加入&lt;img src="<span class="hilite3">Captcha</span>.jpg"&gt;即可显示生成的验证码</p>
				<p> </p>
				<p> 3、后台验证<br /> 验证非常简单，通过session.getAttribute(<span class="hilite2">nl</span>.<span class="hilite3">captcha</span>.<span class="hilite4">servlet</span>.Constants.SIMPLE_CAPCHA_SESSION_KEY);即可得到组件生成<br />的验证码，然后与前台传递的用户填写的内容比较即可。<br /> <br /> 注：如果要自定义验证码的内容可以继承DefaultTextCreator类，覆写getText()方法即可，方法返回的是一个字符串。</p>
				<p> </p>
				<p>　　二、JCAPTCHA，该组件功能非常强大，可以生成word、图片、声音等验证码。主页：<br /> <a href="http://forge.octo.com/jcaptcha/confluence/display/general/Home">http://forge.octo.com/jcaptcha/confluence/display/general/Home</a><br /> <a href="http://jcaptcha.sourceforge.net/">http://jcaptcha.sourceforge.net/</a></p>
				<p> </p>
				<p>
						<img alt="example" />
						<br /> 更多实例可以查看：<a href="http://forge.octo.com/jcaptcha/confluence/display/general/Samples+tests">http://forge.octo.com/jcaptcha/confluence/display/general/Samples+tests</a></p>
				<p>
						<br /> 1、配置<br /> 下载JCAPTCHA后将jcaptcha.jar和commons-collections-2.1以上.jar(单独下载，地址：<a href="http://commons.apache.org/collections/">http://commons.apache.org/collections/</a>)放置工程lib目录下。</p>
				<p> </p>
				<p> 2、Implement a CaptchaService</p>
				<p> import com.octo.<span class="hilite3">captcha</span>.service.image.ImageCaptchaService;<br /> import com.octo.<span class="hilite3">captcha</span>.service.image.DefaultManageableImageCaptchaService;</p>
				<p> public class CaptchaServiceSingleton {</p>
				<p>     private static ImageCaptchaService instance = new DefaultManageableImageCaptchaService();</p>
				<p>     public static ImageCaptchaService getInstance(){<br />         return instance;<br />     　　}<br /> }</p>
				<p> </p>
				<p> 3、编写一个产生验证码的<span class="hilite4">servlet</span><br /> <br /> public class ImageCaptchaServlet extends HttpServlet {<br /> <br /> protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) <br />       throws ServletException, IOException {</p>
				<p>        byte[] captchaChallengeAsJpeg = null;<br />      <br />        ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();<br />        try {<br />        String captchaId = httpServletRequest.getSession().getId();<br />        <br />         BufferedImage challenge =<br />                    CaptchaServiceSingleton.getInstance().getImageChallengeForID(captchaId,<br />                            httpServletRequest.getLocale());<br />            JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(jpegOutputStream);<br />            jpegEncoder.encode(challenge);<br />        } catch (IllegalArgumentException e) {<br />            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);<br />            return;<br />        } catch (CaptchaServiceException e) {<br />            httpServletResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);<br />            return;<br />        }</p>
				<p>        captchaChallengeAsJpeg = jpegOutputStream.toByteArray();</p>
				<p>        httpServletResponse.setHeader("Cache-Control", "no-store");<br />        httpServletResponse.setHeader("Pragma", "no-cache");<br />        httpServletResponse.setDateHeader("Expires", 0);<br />        httpServletResponse.setContentType("image/jpeg");<br />        ServletOutputStream responseOutputStream =<br />                httpServletResponse.getOutputStream();<br />        responseOutputStream.write(captchaChallengeAsJpeg);<br />        responseOutputStream.flush();<br />        responseOutputStream.close();<br />    }<br />}</p>
				<p>
						<br /> 4、将<span class="hilite4">servlet</span>添加到web.xml文件中<br /> &lt;<span class="hilite4">servlet</span>&gt;<br />         &lt;<span class="hilite4">servlet</span>-name&gt;jcaptcha&lt;/<span class="hilite4">servlet</span>-name&gt;<br />         &lt;<span class="hilite4">servlet</span>-class&gt;ImageCaptchaServlet&lt;/<span class="hilite4">servlet</span>-class&gt;<br />         &lt;load-on-startup&gt;0&lt;/load-on-startup&gt;<br />        &lt;/<span class="hilite4">servlet</span>&gt;</p>
				<p> &lt;<span class="hilite4">servlet</span>-mapping&gt;<br />         &lt;<span class="hilite4">servlet</span>-name&gt;jcaptcha&lt;/<span class="hilite4">servlet</span>-name&gt;<br />         &lt;url-pattern&gt;/jcaptcha&lt;/url-pattern&gt;<br /> &lt;/<span class="hilite4">servlet</span>-mapping&gt;</p>
				<p> </p>
				<p> 5、在页面中显示<br /> &lt;img src="jcaptcha"&gt;<br /> &lt;input type='text' name='captcha_code' value=''&gt;</p>
				<p> </p>
				<p> 6、后台验证<br /> Boolean isResponseCorrect =Boolean.FALSE;<br />        String captchaId = httpServletRequest.getSession().getId();<br />        String response = httpServletRequest.getParameter("captcha_code");<br />        try {<br />                isResponseCorrect = CaptchaServiceSingleton.getInstance().validateResponseForID(captchaId,response);<br />        } catch (CaptchaServiceException e) {<br />  //TODO<br />        }<br /> 最简单的开发过程结束，试运行一下效果！<br /> <br /> 注：要实现自己的验证引擎可以继承ListImageCaptchaEngine实现抽象方法buildInitialFactories()。</p>
		</div>
<img src ="http://www.blogjava.net/libin2722/aggbug/288850.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/libin2722/" target="_blank">礼物</a> 2009-07-29 10:37 <a href="http://www.blogjava.net/libin2722/articles/288850.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java 国际化-资源文件的使用 (i18n)</title><link>http://www.blogjava.net/libin2722/articles/207836.html</link><dc:creator>礼物</dc:creator><author>礼物</author><pubDate>Sat, 14 Jun 2008 03:01:00 GMT</pubDate><guid>http://www.blogjava.net/libin2722/articles/207836.html</guid><wfw:comment>http://www.blogjava.net/libin2722/comments/207836.html</wfw:comment><comments>http://www.blogjava.net/libin2722/articles/207836.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/libin2722/comments/commentRss/207836.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/libin2722/services/trackbacks/207836.html</trackback:ping><description><![CDATA[<h3>Java国际化——资源包的使用</h3>
<br />
<u>本文是由JR主持写作的《J2SE进阶》一书的部分章节整理而成，《J2SE进阶》正在写作、完善阶段。您阅读后，有任何建议、批评，请<a class="l2" href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#111;&#107;&#95;&#119;&#105;&#110;&#110;&#101;&#114;&#98;&#111;&#121;&#64;&#115;&#105;&#110;&#97;&#46;&#99;&#111;&#109;" target="_blank">和我联系</a>，或在<a href="http://www.chinaitpower.com/A200507/2005-07-24/&nbsp;%3Ca%20href=%22http://www.javaresearch.org/forum/thread.jsp?column=376&amp;thread=7576"  ?>http://www.javaresearch.org/forum/thread.jsp?column=376&amp;thread=7576'</a> target='_blank' class='l2'&gt;这儿留言</a>。《J2SE进阶》写作项目组感谢您阅读本文。</u><br />
<br />
在当今这个信息社会，尤其是随着互联网的出现和普及，人们之间的距离比以往任何时候都更加接近，同时交往也更加频繁，时下最时髦的概念就是地球村，而我小时候只知道我出生的那个小乡村。距离近，交往频繁，人们就不得不考虑如何去与各个不同种族、不同区域的人们打交道。对人如此，对我们的软件亦是如此，你需要考虑如何让处于世界不同地方的使用者都能够很好地使用你的软件。于是，在每个软件开始之前，编写者都可能需要考虑这样一个问题——国际化。<br />
<br />
我们知道，在Java中可以通过java.util.Locale类来唯一地确定特定语言和国家的组合，即抽象最终用户的使用环境。同时将用户相关的一些信息置于资源包中，通过资源包来动态地获得最终的用户显示。资源包可以由资源文件或者资源子类来具体实现。<br />
<strong><br />
注意：本文只打算讨论国际化过程中资源包的使用技巧，更多更精彩的内容，请期待《J2SE进阶》一书。</strong><br />
<br />
<h4>资源包</h4>
<br />
在编写应用程序的时候，需要面对的一个问题是如何来处理与locale相关的一些信息。比如，页面上的一些静态文本就希望能够以用户习惯的语言显示。最原始的做法是将这些信息硬编码到程序中（可能是一大串判断语句），但是这样就将程序代码和易变的locale信息捆绑在一起，以后如果需要修改locale信息或者添加其它的locale信息，你就不得不重新修改代码。而资源包可以帮助你解决这个问题，它通过将可变的locale信息放入资源包中来达到两者分离的目的。应用程序可以自动地通过当前的locale设置到相应的资源包中取得所要的信息。资源包的概念类似于Windows编程人员使用的资源文件（rc文件）。<br />
<br />
一般来说，资源包需要完成两个功能：和具体的locale进行绑定以及读取locale相关信息。<br />
<br />
<h5>ResourceBundle类</h5>
<br />
你可以把资源包看作为一个由许多成员（子类）组成的大家庭，其中每个成员关联到不同的locale对象，那它是如何完成关联功能的呢？<br />
<br />
资源包中的每个成员共享一个被称作基名（base&nbsp;name）的名称，然后在此基础上根据一定的命名规范进行扩展。下面就列出了一些成员的名称：<br />
&nbsp;&nbsp;&nbsp;&nbsp;LabelResources<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LabelResources_de<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LabelResources_de_CH<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LabelResources_de_CH_UNIX<br />
可见这些子类依据这样的命名规范：baseName_language_country_variant，其中language等几个变量就是你在构造Locale类时所使用的。而资源包正是通过这个符合命名规范的名称来和locale进行关联的，比如LabelResource_de_CH就对应于由德语（de）和瑞士（CH）组成的locale对象。<br />
<br />
当你的应用程序需要查找特定locale对象关联的资源包时，它可以调用ResourceBundle的getBundle方法，并将locale对象作为参数传入。<br />
<div class="codeStyle">
<ol>
    <li>
    <li><font color="#ff0000">Locale</font>&nbsp;currentLocale&nbsp;=&nbsp;<strong><font color="#0000ff">new</font></strong>&nbsp;<font color="#ff0000">Locale</font>(<font color="#ff33ff">"de"</font>,&nbsp;<font color="#ff33ff">"CH"</font>,&nbsp;<font color="#ff33ff">"UNIX"</font>);
    <li><font color="#ff0000">ResourceBundle</font>&nbsp;myResources&nbsp;=
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ff0000">ResourceBundle</font>.getBundle(<font color="#ff33ff">"LabelResources"</font>,&nbsp;currentLocale); </li>
</ol>
</div>
<br />
如果该locale对象匹配的资源包子类找不到，getBundle将试着查找最匹配的一个子类。具体的查找策略是这样的：getBundle使用基名，locale对象和缺省的locale来生成一个候选资源包名称序列。如果特定locale对象的语言代码、国家代码和可选变量都是空值，则基名是唯一的候选资源包名称。否则的话，具体locale对象（language1，country1和variant1）和缺省locale（language2，country2和variant2）将产生如下的序列：<br />
<ul><br />
    <li>baseName&nbsp;+&nbsp;"_"&nbsp;+&nbsp;language1&nbsp;+&nbsp;"_"&nbsp;+&nbsp;country1&nbsp;+&nbsp;"_"&nbsp;+&nbsp;variant1<br />
    <li>baseName&nbsp;+&nbsp;"_"&nbsp;+&nbsp;language1&nbsp;+&nbsp;"_"&nbsp;+&nbsp;country1&nbsp;<br />
    <li>baseName&nbsp;+&nbsp;"_"&nbsp;+&nbsp;language1&nbsp;<br />
    <li>baseName&nbsp;+&nbsp;"_"&nbsp;+&nbsp;language2&nbsp;+&nbsp;"_"&nbsp;+&nbsp;country2&nbsp;+&nbsp;"_"&nbsp;+&nbsp;variant2&nbsp;<br />
    <li>baseName&nbsp;+&nbsp;"_"&nbsp;+&nbsp;language2&nbsp;+&nbsp;"_"&nbsp;+&nbsp;country2&nbsp;<br />
    <li>baseName&nbsp;+&nbsp;"_"&nbsp;+&nbsp;language2&nbsp;<br />
    <li>baseName&nbsp;<br />
    </li>
</ul>
<br />
然后，getBundle方法按照产生的序列依次查找匹配的资源包子类并对结果子类初始化。首先，它将寻找类名匹配候选资源包名称的类，如果找到将创建该类的一个实例，我们称之为结果资源包。否则，getBundle方法将寻找对应的资源文件，它通过候选资源包名称来获得资源文件的完整路径（将其中的&#8220;.&#8221;替换为&#8220;/&#8221;，并加上&#8220;.properties&#8221;后缀），如果找到匹配文件，getBundle方法将利用该资源文件来创建一个PropertyResourceBundle实例，也就是最终的结果资源包。与此同时，getBundle方法会将这些资源包实例缓存起来供以后使用。<br />
<br />
如果没有找到结果资源包，该方法将抛出MissingResourceException异常。所以为了防止异常的抛出，一般来说都需要至少实现一个基名资源包子类。<br />
<br />
<strong>注意：基名参数必须是一个完整的类名称（比如LabelResources，resource.LabelResources等），就相当于你引用一个类时需要指定完整的类路径。但是，为了和以前的版本保持兼容，在使用PropertyResourceBundles时也允许使用&#8220;/&#8221;来代替&#8220;.&#8221;表示路径。</strong><br />
<br />
比如你有以下这些资源类和资源文件：MyResources.class，&nbsp;MyResources_fr_CH.properties，&nbsp;MyResources_fr_CH.class，&nbsp;MyResources_fr.properties，&nbsp;MyResources_en.properties，&nbsp;MyResources_es_ES.class。你利用以下的locale设置来调用getBundle方法，你将会得到不同的结果资源包（假设缺省locale为Locale(&#8220;en&#8221;,&nbsp;&#8220;UK&#8221;)），请参考表13.4。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;表13.4&nbsp;locale设置与结果资源包<br />
locale设置&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;结果资源包<br />
Locale("fr",&nbsp;"CH")&nbsp;&nbsp;&nbsp;&nbsp;MyResources_fr_CH.class<br />
Locale("fr",&nbsp;"FR")&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MyResources_fr.properties<br />
Locale("de",&nbsp;"DE")&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MyResources_en.properties<br />
Locale("en",&nbsp;"US")&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MyResources_en.properties<br />
Locale("es",&nbsp;"ES")&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MyResources_es_ES.class<br />
<br />
创建了具体的资源包子类实例以后，就需要获得具体的信息。信息在资源包中是以键值对的方式存储的，表13.5列出的是LabelResources.properties文件的内容。<br />
<br />
表13.5&nbsp;LabelResources.properties<br />
<div class="codeStyle">
<ol>
    <li>
    <li>#&nbsp;This&nbsp;is&nbsp;LabelResources.properties&nbsp;file
    <li>greetings&nbsp;=&nbsp;您好！
    <li>farewell&nbsp;=&nbsp;再见。
    <li>inquiry&nbsp;=&nbsp;您好吗？ </li>
</ol>
</div>
<br />
其中等号左边的字符串表示主键，它们是唯一的。为了获得主键对应的值，你可以调用ResourceBundle类的getString方法，并将主键作为参数。此外，文件中以&#8220;#&#8221;号开头的行表示注释行。<br />
<br />
<h5>ListResourceBundle和PropertyResourceBundle子类</h5>
<br />
抽象类ResourceBundle具有两个子类：ListResourceBundle和PropertyResourceBundle，它们表示资源包子类两种不同的实现方式。<br />
<br />
PropertyResourceBundle是和资源文件配对使用的，一个属性文件就是一个普通的文本文件，你只需要为不同的locale设置编写不同名称的资源文件。但是，在资源文件中只能包含字符串，如果需要存储其它类型对象，你可以使用ListResourceBundle。<br />
<br />
ListResourceBundle是将键值对信息保存在类中的列表中，而且你必须实现ListResourceBundle的具体子类。<br />
<br />
如果ListResourceBundle和PropertyResourceBundle不能够满足你的需要，你可以实现自己的ResourceBundle子类，你的子类必须覆盖两个方法：handleGetObject和getKeys。<br />
<br />
<h5>使用资源文件</h5>
<br />
使用资源包最简单的方法就是利用资源文件，利用资源文件一般需要以下几个步骤：<br />
1、创建一个缺省的资源文件<br />
为了防止找不到资源文件，你最好实现一个缺省的资源文件，该文件的名称为资源包的基名加上.properties后缀。<br />
2、创建所需的资源文件<br />
为你准备支持的locale设置编写对应的资源文件。<br />
3、设置locale<br />
你必须在程序中的某个地方提供locale的设置或者切换功能，或者将其放入配置文件中。<br />
4、根据locale设置创建资源包<br />
ResourceBundle&nbsp;resource&nbsp;=<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ResourceBundle.getBundle("LabelBundle",currentLocale);<br />
5、通过资源包获取locale相关信息<br />
String&nbsp;value&nbsp;=&nbsp;resource.getString("welcome");<br />
<br />
<strong>注意：在使用基名的时候，特别要注意给出完整的类名（或者路径名），比如你的应用程序所在的类包为org.javaresearch.j2seimproved.i18n，而你的资源文件在你的应用程序下的resource子目录中，那你的基名就应该是org.javaresearch.j2seimproved.i18n.resource.LabelBundleBundle而不是resource.LabelBundleBundle。<br />
</strong><br />
<br />
<h5>使用ListResourceBundle</h5>
<br />
使用ListResourceBundle和使用资源文件的步骤基本上一样，只不过你需要用ListResourceBundle子类来替换相应的资源文件。比如你的应用程序的基名是LabelBundle，而且准备支持Locale("en","US")和Locale("zh","CN")，那你需要提供以下几个Java文件，注意类名和locale的对应关系。<br />
LabelBundle_en_US.java<br />
LabelBundle_zh_CN.java<br />
LabelBundle.java（缺省类）<br />
<br />
代码13.3列出的是LabelBundle_zh_CN.java的源代码，相对于资源文件中&#8220;key&nbsp;=&nbsp;value&#8221;的写法，在此文件中你首先利用键值对来初始化一个二维数组，并在getContents方法中返回该数组。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
代码13.3：LabelBundle_zh_CN.java<br />
<div class="codeStyle">
<ol>
    <li>
    <li><strong><font color="#0000ff">package</font></strong>&nbsp;org.javaresearch.j2seimproved.i18n;<strong><font color="#0000ff">import</font></strong>&nbsp;
    <li>
    <li>java.util.<strong><a href="http://www.chinaitpower.com/source/jdk142/java/util/ListResourceBundle.java.html" target="_blank"><font class="classLink"><u>ListResourceBundle</u></font></a></strong>;
    <li>
    <li><strong><font color="#0000ff">public</font></strong>&nbsp;<strong><font color="#0000ff">class</font></strong>&nbsp;LabelBundle_zh_CN&nbsp;<strong><font color="#0000ff">extends</font></strong>&nbsp;<font color="#ff0000">ListResourceBundle</font>&nbsp;{&nbsp;&nbsp;&nbsp;
    <li>&nbsp;&nbsp;<strong><font color="#0000ff">public</font></strong>&nbsp;<strong><a href="http://www.chinaitpower.com/source/jdk142/java/lang/Object.java.html" target="_blank"><font class="classLink"><u>Object</u></font></a></strong>[][]&nbsp;getContents()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    <li>&nbsp;&nbsp;&nbsp;&nbsp;<strong><font color="#0000ff">return</font></strong>&nbsp;contents;&nbsp;&nbsp;&nbsp;
    <li>&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;
    <li>
    <li>&nbsp;&nbsp;<strong><font color="#0000ff">private</font></strong>&nbsp;<strong><a href="http://www.chinaitpower.com/source/jdk142/java/lang/Object.java.html" target="_blank"><font class="classLink"><u>Object</u></font></a></strong>[][]&nbsp;contents&nbsp;=&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    <li>&nbsp;&nbsp;&nbsp;&nbsp;{<font color="#ff33ff">"title"</font>,&nbsp;<font color="#ff33ff">"称谓"</font>},&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    <li>&nbsp;&nbsp;&nbsp;&nbsp;{<font color="#ff33ff">"surname"</font>,&nbsp;<font color="#ff33ff">"姓"</font>},&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    <li>&nbsp;&nbsp;&nbsp;&nbsp;{<font color="#ff33ff">"firstname"</font>,&nbsp;<font color="#ff33ff">"名"</font>},&nbsp;&nbsp;&nbsp;
    <li>&nbsp;&nbsp;};
    <li>} </li>
</ol>
</div>
<br />
<br />
创建完资源类以后，同样需要设置locale以及根据locale来创建资源包。在通过资源包获取具体值的时候，你不能再使用getString方法，而应该调用getObject方法，而且由于getObject方法返回一个Object对象，你还需要进行正确的类型转换。其实，为了你的程序通用性，我们建议在使用资源文件的时候你也应该调用getObject方法，而不是getString方法。<br />
<div class="codeStyle">
<ol>
    <li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;<strong><a href="http://www.chinaitpower.com/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></strong>&nbsp;title&nbsp;=&nbsp;(<strong><a href="http://www.chinaitpower.com/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></strong>)resource.getObject(<font color="#ff33ff">"title"</font>); </li>
</ol>
</div>
<br />
关于ListResourceBundle的详细使用，可以参考本书所附代码中国际化一节的ListResourceBundleSample.java程序。<br />
<br />
<h5>MessageFormat类</h5>
<br />
上面我们讲到利用资源文件来分离代码和可变的信息。但是在实际过程中，有些信息并不能够完全事先定义好，其中可能会用到运行时的一些结果，最典型例子的就是错误提示代码，比如提示某个输入必须在一定范围内。利用上面所讲的资源文件并不能够很好地解决这个问题，所以Java中引入了MessageFormat类。<br />
<br />
MessageFormat提供一种语言无关的方式来组装消息，它允许你在运行时刻用指定的参数来替换掉消息字符串中的一部分。你可以为MessageFormat定义一个模式，在其中你可以用占位符来表示变化的部分，比如你有这样一句话：<br />
<br />
您好，<u>peachpi</u>！欢迎来到Java研究组织网站！当前时间是：<u>2003-8-1&nbsp;16:43:12。</u><br />
<br />
其中斜体带下划线的部分为可变化的，你需要根据当前时间和不同的登录用户来决定最终的显示。我们用占位符来表示这些变化的部分，可以得到下面这个模式：<br />
<br />
您好，{0}！欢迎来到Java研究组织网站！当前时间是：{1,date}&nbsp;{1,time}。<br />
<br />
占位符的格式为{&nbsp;ArgumentIndex&nbsp;,&nbsp;FormatType&nbsp;,&nbsp;FormatStyle&nbsp;}，详细说明可以参考MessageFormat的API说明文档。这里我们定义了两个占位符，其中的数字对应于传入的参数数组中的索引，{0}占位符被第一个参数替换，{1}占位符被第二个参数替换，依此类推。<br />
最多可以设置10个占位符，而且每个占位符可以重复出现多次，而且格式可以不同，比如{1,date}和{1,time}。而通过将这些模式定义放到不同的资源文件中，就能够根据不同的locale设置，得到不同的模式定义，并用参数动态替换占位符。<br />
<br />
下面我们就以MessageFormatSample.java程序（源文件见本书所附代码）为例，来详细说明其中的每个步骤。<br />
1、找出可变的部分，并据此定义模式，将模式放入不同的资源文件中。<br />
比如针对上面的模式，定义了下面两个资源文件：<br />
MessagesBundle_en_US.properties<br />
Welcome&nbsp;=&nbsp;Hi,&nbsp;{0}!&nbsp;Welcome&nbsp;to&nbsp;Java&nbsp;Research&nbsp;Organization!<br />
MessagesBundle_zh_CN.properties<br />
Welcome&nbsp;=&nbsp;您好，{0}！欢迎来到Java研究组织网站！<br />
<br />
2、创建MessageFormat对象，并设置其locale属性。<br />
<div class="codeStyle">
<ol>
    <li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ff0000">MessageFormat</font>&nbsp;formatter&nbsp;=&nbsp;<strong><font color="#0000ff">new</font></strong>&nbsp;<font color="#ff0000">MessageFormat</font>(<font color="#ff33ff">""</font>);
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;formatter.setLocale(currentLocale); </li>
</ol>
</div>
<br />
3、从资源包中得到模式定义，以及设置参数。<br />
<div class="codeStyle">
<ol>
    <li>
    <li>messages&nbsp;=&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ff0000">ResourceBundle</font>.getBundle(
    <li>&nbsp;&nbsp;<font color="#ff33ff">"org.javaresearch.j2seimproved.i18n.resource.MessagesBundle"</font>,currentLocale);
    <li><strong><a href="http://www.chinaitpower.com/source/jdk142/java/lang/Object.java.html" target="_blank"><font class="classLink"><u>Object</u></font></a></strong>[]&nbsp;testArgs&nbsp;=&nbsp;{<font color="#ff33ff">"peachpi"</font>,<strong><font color="#0000ff">new</font></strong>&nbsp;<font color="#ff0000">Date</font>()}; </li>
</ol>
</div>
<br />
4、利用模式定义和参数进行格式化。<br />
<div class="codeStyle">
<ol>
    <li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><a href="http://www.chinaitpower.com/source/jdk142/java/lang/System.java.html" target="_blank"><font class="classLink"><u>System</u></font></a></strong>.out.println(formatter.format(messages.getString(<font color="#ff33ff">"welcome"</font>),testArgs)); </li>
</ol>
</div>
<br />
<br />
<h5>关于资源包的组织</h5>
<br />
一般来说，你是按照资源的用途来组织资源包的，比如会把所有的页面按钮的信息放入一个名为ButtonResources的资源包中。在实际的应用过程中，以下几个原则可以帮你决定如何组织资源包：<br />
1、要易于维护。<br />
2、最好不要将所有的信息都放入一个资源包中，因为这样资源包载入内存时将会很耗时。<br />
3、最好将一个大的资源包分为几个小的资源包，这样可以在使用的时候才导入必须的资源，减少内存消耗。
<img src ="http://www.blogjava.net/libin2722/aggbug/207836.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/libin2722/" target="_blank">礼物</a> 2008-06-14 11:01 <a href="http://www.blogjava.net/libin2722/articles/207836.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>提升JSP页面响应速度的七大秘籍绝招</title><link>http://www.blogjava.net/libin2722/articles/192507.html</link><dc:creator>礼物</dc:creator><author>礼物</author><pubDate>Sun, 13 Apr 2008 01:02:00 GMT</pubDate><guid>http://www.blogjava.net/libin2722/articles/192507.html</guid><wfw:comment>http://www.blogjava.net/libin2722/comments/192507.html</wfw:comment><comments>http://www.blogjava.net/libin2722/articles/192507.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/libin2722/comments/commentRss/192507.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/libin2722/services/trackbacks/192507.html</trackback:ping><description><![CDATA[你时常被客户抱怨JSP页面响应速度很慢吗？你想过当客户访问次数剧增时，你的WEB应用能承受日益增加的访问量吗？本文讲述了调整JSP和
servlet的一些非常实用的方法，它可使你的servlet和JSP页面响应更快，扩展性更强。而且在用户数增加的情况下，系统负载会呈现出平滑上长
的趋势。在本文中，我将通过一些实际例子和配置方法使得你的应用程序的性能有出人意料的提升。<br />
<br />
其中，某些调优技术是在你的编程工作中实现的。而另一些技术是与应用服务器的配置相关的。在本文中，我们将详细地描述怎样通过调整servlet和JSP页面，来提高你的应用程序的总体性能。在阅读本文之前，假设你有基本的servlet和JSP的知识。<br />
<br />
<strong>方法一：在servlet的init()方法中缓存数据<br />
</strong><br />
当应用服务器初始化servlet实例之后，为客户端请求提供服务之前，它会调用这个servlet的init()方法。在一个servlet的生命周
期中，init()方法只会被调用一次。通过在init()方法中缓存一些静态的数据或完成一些只需要执行一次的、耗时的操作，就可大大地提高系统性能。<br />
<br />
例如，通过在init()方法中建立一个JDBC连接池是一个最佳例子，假设我们是用jdbc2.0的DataSource接口来取得数据库连接，在通
常的情况下，我们需要通过JNDI来取得具体的数据源。我们可以想象在一个具体的应用中，如果每次SQL请求都要执行一次JNDI查询的话，那系统性能将
会急剧下降。解决方法是如下代码，它通过缓存DataSource，使得下一次SQL调用时仍然可以继续利用它：<br />
<br />
<center>
<table bordercolordark="#ffffff" bordercolorlight="black" align="center" border="1" cellpadding="2" cellspacing="0" width="400">
    <tbody>
        <tr>
            <td class="code">
            <pre>public class ControllerServlet extends HttpServlet<br />
            <br />
            {<br />
            <br />
            private javax.sql.DataSource testDS = null; <br />
            <br />
            public void init(ServletConfig config) throws ServletException<br />
            <br />
            {<br />
            <br />
            super.init(config); <br />
            <br />
            Context ctx = null;<br />
            <br />
            try<br />
            <br />
            { <br />
            <br />
            ctx = new InitialContext();<br />
            <br />
            testDS = (javax.sql.DataSource)ctx.lookup("jdbc/testDS");<br />
            <br />
            }<br />
            <br />
            catch(NamingException ne)<br />
            <br />
            {<br />
            <br />
            ne.printStackTrace(); <br />
            <br />
            }<br />
            <br />
            catch(Exception e)<br />
            <br />
            {<br />
            <br />
            e.printStackTrace();<br />
            <br />
            }<br />
            <br />
            }<br />
            <br />
            public javax.sql.DataSource getTestDS()<br />
            <br />
            {<br />
            <br />
            return testDS;<br />
            <br />
            }<br />
            <br />
            ...<br />
            <br />
            ... <br />
            <br />
            }</pre>
            </td>
        </tr>
    </tbody>
</table>
</center>
<p>　　<strong>方法 2:禁止servlet和JSP 自动重载(auto-reloading)</strong> <br />
<br />
Servlet/JSP提供了一个实用的技术，即自动重载技术，它为开发人员提供了一个好的开发环境，当你改变servlet和JSP页面后而不必重启应
用服务器。然而，这种技术在产品运行阶段对系统的资源是一个极大的损耗，因为它会给JSP引擎的类装载器(classloader)带来极大的负担。因此
关闭自动重载功能对系统性能的提升是一个极大的帮助。</p>
<p>　　<strong>方法 3: 不要滥用HttpSession</strong> <br />
<br />
在很多应用中，我们的程序需要保持客户
端的状态，以便页面之间可以相互联系。但不幸的是由于HTTP具有天生无状态性，从而无法保存客户端的状态。因此一般的应用服务器都提供了session
来保存客户的状态。在JSP应用服务器中，是通过HttpSession对像来实现session的功能的，但在方便的同时，它也给系统带来了不小的负
担。因为每当你获得或更新session时，系统者要对它进行费时的序列化操作。你可以通过对HttpSession的以下几种处理方式来提升系统的性
能。<br />
<br />
如果没有必要，就应该关闭JSP页面中对HttpSession的缺省设置。 如果你没有明确指定的话，每个JSP页面都会缺省地创建一个HttpSession。如果你的JSP中不需要使用session的话，那可以通过如下的JSP页面指示符来禁止它：</p>
<center>
<table bordercolordark="#ffffff" bordercolorlight="black" align="center" border="1" cellpadding="2" cellspacing="0" width="400">
    <tbody>
        <tr>
            <td class="code">
            <pre>＜%@ page session="false"%＞</pre>
            </td>
        </tr>
    </tbody>
</table>
</center>
<p>　　不要在HttpSession中存放大的数据对像：如果你在HttpSession中存放大的数据对像的话，每当对它进行读写时，应用服务器都
将对其进行序列化，从而增加了系统的额外负担。你在HttpSession中存放的数据对像越大，那系统的性能就下降得越快。 <br />
<br />
当
你不需要HttpSession时，尽快地释放它：当你不再需要session时，你可以通过调用HttpSession.invalidate()方法
来释放它。尽量将session的超时时间设得短一点：在JSP应用服务器中，有一个缺省的session的超时时间。当客户在这个时间之后没有进行任何
操作的话，系统会将相关的session自动从内存中释放。超时时间设得越大，系统的性能就会越低，因此最好的方法就是尽量使得它的值保持在一个较低的水
平。 <br />
<br />
方法 4: 将页面输出进行压缩 <br />
<br />
压缩是解决数据冗余的一个好的方法，特别是在网络带宽不够发达的今天。有的浏
览器支持gzip(GNU
zip)进行来对HTML文件进行压缩，这种方法可以戏剧性地减少HTML文件的下载时间。因此，如果你将servlet或JSP页面生成的HTML页面
进行压缩的话，那用户就会觉得页面浏览速度会非常快。但不幸的是，不是所有的浏览器都支持gzip压缩，但你可以通过在你的程序中检查客户的浏览器是否支
持它。下面就是关于这种方法实现的一个代码片段： </p>
<ccid_nobr>
</ccid_nobr>
<pre>public void doGet(HttpServletRequest request, <br />
<br />
HttpServletResponse response)<br />
<br />
throws IOException, ServletException <br />
<br />
{<br />
<br />
OutputStream out = null<br />
<br />
String encoding = request.getHeader("Accept-Encoding"); <br />
<br />
if (encoding != null &amp;&amp; encoding.indexOf("gzip") != -1)<br />
<br />
{<br />
<br />
request.setHeader("Content-Encoding" , "gzip");<br />
<br />
out = new GZIPOutputStream(request.getOutputStream());<br />
<br />
}<br />
<br />
else if (encoding != null &amp;&amp; encoding.indexOf("compress") != -1)<br />
<br />
{<br />
<br />
request.setHeader("Content-Encoding" , "compress");<br />
<br />
out = new ZIPOutputStream(request.getOutputStream());<br />
<br />
} <br />
<br />
else<br />
<br />
{<br />
<br />
out = request.getOutputStream();<br />
<br />
}<br />
<br />
...<br />
<br />
... <br />
<br />
}</pre>
<img src ="http://www.blogjava.net/libin2722/aggbug/192507.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/libin2722/" target="_blank">礼物</a> 2008-04-13 09:02 <a href="http://www.blogjava.net/libin2722/articles/192507.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jsp 70 问答</title><link>http://www.blogjava.net/libin2722/articles/158058.html</link><dc:creator>礼物</dc:creator><author>礼物</author><pubDate>Sun, 04 Nov 2007 04:59:00 GMT</pubDate><guid>http://www.blogjava.net/libin2722/articles/158058.html</guid><wfw:comment>http://www.blogjava.net/libin2722/comments/158058.html</wfw:comment><comments>http://www.blogjava.net/libin2722/articles/158058.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/libin2722/comments/commentRss/158058.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/libin2722/services/trackbacks/158058.html</trackback:ping><description><![CDATA[jsp问答７０问：<br />
1. 问：在JAVA与JSP中要调用一个LINUX上的脚本程序,或WINDOWS上的脚本程序,该怎么写？<br />
答：System.getRuntime().exec("bash &lt; aaa.sh");<br />
<br />
2. 问：java中用什么表示双引号<br />
答："""<br />
<br />
3. 问：如何在JSP程序里另起一个线程？<br />
答：<br />
JSP本身就是独立线程运行而不象CGI都是独立进程.<br />
一般:<br />
Thread t = new Thread("你的对象");<br />
t.start();就可以了.<br />
要求你这个对象要实现runnable接口或继承thread.<br />
<br />
4. 问：jsp如何获得客户端的IP地址？<br />
答：<br />
request.getRemoteAddr()<br />
看看各个webserver的API文档说明，一般都有自带的，resin和tomcat都有<br />
<br />
5. 问：程序终止与输出终止<br />
答：<br />
程序中止:return;<br />
输出中止out.close();这一句相当于ASP的response.end<br />
<br />
6. 问：jsp中如何得到上页的URL？<br />
答：request.getHeader("referer");<br />
<br />
7. 问：提交网页的网页过期功能是怎么做的？<br />
答：response.setHader("Expires","0");<br />
<br />
8. 问：在JSP网页中如何知道自已打开的页面的名称<br />
答：<br />
request.getRequestURI() ;//文件名<br />
request.getRequestURL() ;//全部ＵＲＬ<br />
<br />
9. 问：提交表单后验证没有通过，返回提交页面，如何使原提交页面中的数据保留？<br />
答：javascript的go(-1)可以把上页的表单内容重新显示出来,但password域没有<br />
<br />
10. 问：如何取得http的头信息？<br />
答：request.getHader(headerName);<br />
<br />
11. 问：&amp;&amp;和&amp;的区别？<br />
答：<br />
&amp;&amp;是短路的与操作，也就是当地一个条件是false的时候，第二个条件不用执行<br />
&amp;相反，两个条件总是执行。<br />
<br />
12. 问：将*以正弦曲线的一个周期显示出来<br />
答：<br />
public void paint(Graphics g)<br />
{<br />
for(int i=0;i&lt;200;i++)<br />
g.drawString("*",i,(int)(Math.sin(i)*20)+50);<br />
}<br />
}<br />
<br />
13. 问：浮点数相乘后结果不精确如100.0 * 0.6 结果等于 60.0004<br />
答：<br />
这不叫错误,float和double是这样实现的.如果要精确计算，java提供了一个strictfp,它的计算遵循IEEE 754标准.而普通的float和double是<br />
<br />
由地平台浮点格式或硬件提供的额外精度或表示范围。<br />
<br />
14. 问：如何获得当前用的cursors的位置？<br />
答：<br />
int row = rs.getRow()就是当前指针行数,还有isFrist();isBeforeFist();isLast();isAfterLast();可以测试是不是在方法名所说的位置<br />
<br />
15. 问：表单成功提交了，点后退显示网页过期<br />
答：<br />
在&lt;head&gt;&lt;/head&gt;里面加以下代码<br />
&lt;META HTTP-EQUIV="Pragma" CONTENT="no-cache"&gt; <br />
&lt;META HTTP-EQUIV="Cache-Control" CONTENT="no-cache"&gt; <br />
&lt;META HTTP-EQUIV="Expires" CONTENT="0"&gt; <br />
或者在表单页中加上<br />
&lt;% <br />
response.setHeader("Pragma","no-cache"); <br />
response.setHeader("Cache-Control","no-cache"); <br />
response.setDateHeader("Expires",0); <br />
%&gt;<br />
<br />
16. 问：接口的简单理解<br />
答：接口为了规范,比如我在接口中定义了一个方法:<br />
getData()<br />
这是用来从不同的数据库中取数据的,就是JDBC的实现对于用户,我不要知道每种数据库是如何做的,但我知道如何它们要实现这个接口就一定有<br />
<br />
这个方法可以供我调用.这样SUN就把这个接口给各个数据库开发商,让他们自己实现. 但为什么不用继承而用接口哩,因为继承只能从一个你类<br />
<br />
继承,而接口可以实现多个,就是说我实现的子类有多个规定好的接口中的功能. 这只是简单的理解,等你深入理解抽象的时候就知道抽象到抽象<br />
<br />
类时为什么还要再抽象到接口.<br />
<br />
17. 问：怎样编写一个取消按钮（怎样返回上一个页面，象工具栏的后退按钮）？<br />
答：<br />
javascript把每次浏览过的location都压到了一个栈中,这个栈就是history,然后你如果要回到第几个页面它就做几次POP操作,把最后POP出来<br />
<br />
的那个LOCATION给你. 这就是JAVASCRIPT在实现history.go(-x)的原理.<br />
<br />
18. 问：什么是回调？<br />
答：<br />
简单说,回调用不是让你去监听谁做完了什么事,而是谁做完了什么事就报告给你. 这就是回调用的思想.例子太多了,AWT的事件,SWING事件模型<br />
<br />
都是这样有. 还有多线程中,如果要控制线程数,不能总是查询每个线程是否结束,要在每个线程结束时让线程自己告诉主线程我结束了,你可以<br />
<br />
开新的线程了.<br />
<br />
19. 问：简要介绍一下compareTo方法<br />
答：<br />
compareTo方法是Comparable 接口必需实现的方法,只要实现Comparable <br />
<br />
就可以用Arrays.srot()排序就象实现Runnable接口的run就能Thread()一样.<br />
<br />
20. 问：如何可以从别的Web服务器检索页, 然后把检索到的网页的HTML代码储存在一个变量中返回过来<br />
答：这是一个简单的WEB ROBOT实现,用URL类实现从网页中抓内容,然后自己写一个分析程序从中找出新的URL,不断递归下去就行了.<br />
<br />
21. 问：applet中如何获得键盘的输入<br />
答：application的System.in是当前系统的标准输入,applet因为安全的原因不可能读取当前系统(客户端)的标准输入,只能从它的ROOT组件的<br />
<br />
事件中,比如键盘事件中取得键值.<br />
<br />
22. 问：怎样计算代码执行所花费的时间？<br />
答：<br />
代码开始取时间，结束后取时间，相减<br />
long t1 = System.currentTimeMillis();<br />
///////////////// your code<br />
long t2 = System.currentTimeMillis() ;<br />
long time = t2-t1;<br />
<br />
23. 问：如何获在程序中获得一个文件的ContentType？<br />
答：<br />
URL u = new URL("file:///aaa.txt");<br />
URLConnection uc = u.openConnection();<br />
String s = uc.getContentType();<br />
<br />
24. 问：连接池的使用是建立很多连接池，还是一个连接池里用多个连接？<br />
答：<br />
只有在对象源不同的情况下才会发生多个池化,如果你只连一结一个数据源,永远不要用多个连结池. 所以连结池的初始化一定要做成静态的,而<br />
<br />
且应该在构造对象之前,也就是只有在类LOAD的时候,别的时候不应该有任何生成新的连结池的时候。<br />
<br />
25. 问：JavaMail要怎么安装？<br />
答：下载两个包，一个是javamail包，另一个是jaf包。下载完直接把这两个包不解压加到CLASSPATH。<br />
<br />
26. 问：怎样把地址栏里的地址锁定？<br />
答：把你的服务器的可访问目录索引选项关闭就行了,任何服务器都有一个conf文件,里面都有这个选项。<br />
<br />
27. 问：在JAVA中怎么取得环境变量啊。比如： TEMP = C：TEMP ？<br />
答：String sss = System.getProperty(key)<br />
<br />
28. 问：怎样实现四舍五入，保留小数点后两位小数？<br />
答：<br />
import java.text.*;<br />
...<br />
NumberFormat nf=NumberFormat.getNumberInstance();<br />
nf.setMaximumFractionDigits(2);<br />
nf.setMinimumFractionDigits(2);<br />
nf.format(numb);<br />
<br />
29. 问：Applet和form如何通信？<br />
答：<br />
取得的参数传到param里面<br />
&lt;% <br />
String xxx = request.getParameter("xxx"); <br />
%&gt; <br />
&lt;applet&gt; <br />
&lt;param value="&lt;%=xxx%&gt;"&gt; <br />
&lt;/applet&gt;<br />
<br />
<br />
30. 问：java-plug-in是什么？<br />
答：Java Runtime Environment的插件。用来运行java程序。不需要什么特别的设置。等于你的机器里面有了jvm。<br />
<br />
31. 问：WEB上面怎么样连接上一个EXCEL表格？<br />
答：<br />
定义页面得contentType="application/vnd.ms-excel"，让页面以excel得形式打开。同样也可以以word得形式打开：application/msword。<br />
<br />
32. 问：怎样才能避免textarea字数限制？<br />
答：是使用了FORM的默认方法的缘故,如果什么也不写默认是GET改用Post即可，在Form中定义mothod="post"。<br />
<br />
33. 问：为什么加了&lt;%@page contentType="text/html;charset=gb2312" %&gt;插入数据库的中文，依然是乱码？<br />
答：<br />
这要从环境看,能显示说明你的JSP引擎没有问题,但写入数据库时你的JDBC能不能处理中文,同一公司不同版本的JDBC都有支持中文和不支持中<br />
<br />
文的情况,RESIN自带的MYSQL JDBC就不支持,MM的就支持,还有你的数据库类型是否支持中文?CHAR的一般支持,但是否用binary存储双字节码<br />
<br />
34. 问：对于JFrame，hide()，show()与setVisibel()有什么区别吗？<br />
答：<br />
setVisible()从Component继承过来，而hide(),show()从Window里面继承过来。<br />
Makes the Window visible. If the Window and/or its owner are not yet displa yable, both are made displayable. The Window will <br />
<br />
be validated prior to being made visible. If t he Window is already visible, this will bring the Window to the front. 区别在<br />
<br />
这。<br />
36. 问：sendRedirect为什么不可以转到mms协议的地址的？response.sendRedirect("mms://missiah.adsldns.org:9394");<br />
答：java平台目前实现的protocol中并没有mms,你可以取系统属性java.protocol.handler.pkgs看看它的值中有没有mms,所以如果要想重定向<br />
<br />
到mms://host这样和URL,只有生成客户端的JAVASCRIPT让它来重定向<br />
<br />
37. 问：JTable中怎样定义各个Columns和Width和怎样设置表格的内容靠做靠右或居中？<br />
答：<br />
TableColumn tc = table.getColumn("Name");//取得列名为"Name"的列Handle<br />
int currentWidth = tc.getPreferredWidth(); //取得该列当前的宽度<br />
tc.setPreferredWidth(200); //设置当前列宽<br />
tc.setMaxWidth(200); //设置该列最大宽度<br />
tc.setMinWidth(50); //设置该列最小宽度<br />
<br />
38. 问：批操作是否可用于select语句？<br />
答：批操作其实是指成批理更新的操作,绝对不可能用于select操作。<br />
<br />
39. 问：为什么jsp路径太深文件名太长就无法读取文件？<br />
答：path不能超过255长度,不然就找不到了.这是作业系统的事。<br />
<br />
40. 问：如何让页面不保留缓存？<br />
答：<br />
&lt;% <br />
response.setHeader("Pragma","No-cache"); <br />
response.setHeader("Cache-Control","no-cache"); <br />
response.setDateHeader("Expires", 0); <br />
%&gt;<br />
<br />
41. 问：我的applet code 中用到jbutton 时就出错是否由于ie不支持swing package 请问应怎么办？<br />
答：JBUTTON是SWING基本包啊,只要把jdk/jre/lib/rt.jar放在classpath就行了.不要加载任何别的库。<br />
<br />
42. 问：不知道java是否支持midi格式，如果支持，应该怎么把wave格式转换成midi格式？<br />
答：目前还不行,可以看一下JMF三个版中对MIDI的格式支持是read only,而WAVE是read/write,MIDI只能播放,不能生成。<br />
<br />
43. 问：在jsp里面防止用户直接输入url进去页面，应该怎么做呢？<br />
答：<br />
一是从web服务器控制,对某一目录的所有访问要通过验证.<br />
二是在要访问的页面中加入控制.这个一般用session,也可以用请求状态码实现<br />
<br />
44. 问：<br />
例如后台有一计算应用程序（此程序运算起来很慢，可持续几分钟到几小时，这不管，主要是能激活它），客户机讲任务提交后，服务器对任<br />
<br />
务进行检测无误后将向服务器后台程序发送信息，并将其激活。要求如下：<br />
1）首先将后台程序激活，让它执行此任务（比如，前台将计算的C代码提交上后，后台程序程序能马上调用，并将其运行）<br />
2）要在前台JSP页面中显示运行过程信息（由于运行时间长，希望让客户看到运行过程中产生的信息）如何完成？<br />
<br />
答：<br />
活是可以的,运行一个shell让它去运行后台就行,但不可能取出运行信息,因为HTTP的超时限制不可能永远等你后台运行的,而且信息如果要动态<br />
<br />
实时推出来就得用SERVER PUSH技术。<br />
<br />
45. 问：数据库是datetime 型 ，插入当前时间到数据库？<br />
答：<br />
java.sql.Date sqlDate = new java.sql.Date();<br />
PreparedStatement pstmt = conn.prepareStatement("insert into foo(time) values(?)");<br />
pstmt.setDate(1,sqlDate);<br />
pstmt.executeUpdate();<br />
<br />
46. 问：怎样去掉字符串前后的空格。<br />
答：String.trim()<br />
<br />
47. 问：session怎样存取int类型的变量？<br />
答：<br />
session.setAttribute("int", i+"");<br />
int i = Integer.parseInt(session.getAttribute("int"));<br />
<br />
48. 问：在javascript中如何使输出的float类型的数据保留两位小数。<br />
答：Math.round(aaaaa*100)/100。<br />
<br />
49. 问：在bean种如何调用session<br />
答：<br />
你可把session对象作为一个参数传给bean<br />
在BEAN中定义HttpServletRequest request;HttpSession session;<br />
然后<br />
session = request.getSession(false);<br />
false为如果session为空,不建立新的session<br />
将session作为参数传入.其实只要将request传入就可以<br />
<br />
50. 问：如何把txt或word文件按原格式显示在jsp页面或servlet上？<br />
答：<br />
其实一个非常简单的解决方法就是在服务器的MIME中指点定TEXT和WORD的解释方式,然后用JSP或SERVLET生成它就行了,客户端就会自动调用相<br />
<br />
应程序打开你的文档。<br />
如果是希望按原格式的显示在页面上，而不是调用其他程序打开那么你可以试试用WEBDEV协议,可以说这是MS的一个亮点.它是在WEB方式下打开<br />
<br />
文档,和共享一样.完全符合的要求。<br />
<br />
51. 问：object的clone方法为什么不能直接调用？<br />
答：<br />
这个方法在object中是protected<br />
为什么要把这个方法定义为protected,这是一个折中,它的目的是想知道你这个方法在Object里只是一个标记,而不是一个实现,比如<br />
<br />
public class Object<br />
{<br />
.............<br />
protected Object clone()<br />
{}<br />
}<br />
<br />
所以直接继承的clone()方法并不能做任何时,你要使用这个方法就要重载这个方法并放宽访问权限为public,或实现cloneable接口. 但它没法<br />
<br />
这样告诉你它没有真的实现,只好用protected 方法加以警示<br />
<br />
52. 问：一个页面中如何刷新另外一个页面？<br />
答：<br />
要求是这些面页必须有关联,一是它们都有一个共同的顶层帧,也就是说是一个帧内的分级页面,当然可以是任意级,帧内再分帧也可以,另一个可<br />
<br />
能是当前窗口弹出的窗口,如果没有联系,那就不可能用一个页面刷新另一个页面. 帧内只要一级一级引用就行了. <br />
<br />
比如在左帧中一个页面中写top.right.location.reload();那么名为right的右帧中的页面就会刷新. 弹出的一样,用open时的名称刷新子窗口,<br />
<br />
子窗口用opener刷新主窗口<br />
<br />
53. 问：如何在jsp中怎么样向客户端写cookies？<br />
答：<br />
Cookie coo = new Cookie(name, value);<br />
HttpServletResponse.addCookie(name);<br />
<br />
54. 问：为什么jTextField1.setText("aaabbb");jTextField2.setText("AAABBB"); 得到的字体宽度不一样？<br />
答：就是说如果不是指定为等宽字体,每个字体的宽度都是不一样的.因此JAVA中用FontMetrics 类来取字符宽度。<br />
<br />
55. 问：String kk=application/octet-stream; name="G:/SMBCrack.exe";如何得到SMBCrack.exe？<br />
答：<br />
这应该是解析上传时候的二进制流得到的这一行里面格式是固定的，取到name="后面的字符串，然后把";去掉。然后取最后一个/后面的所有字<br />
<br />
符组成一个新字符串就行了。<br />
<br />
56. 问：如何传值并不刷新页面？<br />
答：<br />
弹出一个页面进行值的选择或者输入，ok后使用将值传给原窗口，使用javascript关闭打开的窗口即可：<br />
window.close();opener.focus();<br />
<br />
57. 问：有一个字符串："EF0C114EA4"，如何变为a[0] = 0xEF a[1] = 0x0C a[2] = 0x11 a[3] = 0x4E a[4] = 0xA4？<br />
答：<br />
String str="EF0C114EA4F";<br />
out.print(str+"&lt;br&gt;");<br />
int l=str.length()/2+str.length()%2,j=0,k=0;<br />
String[] a=new String[l];<br />
for(int i=0;i&lt;l;i++){<br />
if(str.length()-j==1)<br />
k=str.length();<br />
else<br />
k=j+2;<br />
a="0x"+str.substring(j,k);<br />
out.print("a["+Integer.toString(i)+"]="+a+"&lt;br&gt;");<br />
j+=2;<br />
}<br />
<br />
58. 问：怎样将一个int转换成一个四字节的byte数组？<br />
答：<br />
int x = 1234567;<br />
byte[] b = new byte[4];<br />
for(int i=0;i&lt;b.length;i++)<br />
{<br />
b = (x &gt;&gt;( i*8)) &amp; 0xFF;<br />
}<br />
<br />
59. 问：indexOf()的使用需要注意什么？<br />
答：参数是指从第几位（1，2，3，...）开始搜索，而返回值是指搜索到的位置（0，1，2，3.......）注意是从零算起的。<br />
<br />
60. 问：在Java应用程序中如何动态的添加一个按钮？<br />
答：<br />
这里涉及一个组件重绘的问题,组件要先于panel被显示之处存在,如果一panel已经显示了,那么加在上面你能看到吗?但如果在同一个panel上, <br />
<br />
先有button A,假如按下它加了butt on B,这时你如果使整个panel重给,那么A本身要重绘,它的事件监听就没有了,当然也就加不成B了,所以如<br />
<br />
果要先有另一个panel,当按A时把B加在这个panel上并重绘这个paenl,其实更好的方法是先把B加在panel中,同一个也行.把它setVisiable(flas<br />
<br />
e),按A时设为 true。<br />
<br />
61. 问：book mybook=new book(bookid);book是servlet,出错。<br />
答：<br />
book是servlet,能book mybook=new book(bookid);<br />
说明自己实现了servlet容器?不然,servlet能让你自己去调用? servlet如果调用其实和EJB连1%的区别都没有,它们都是自己继承或实现一些接<br />
<br />
口,在这些父类或接口中实现了如果和容器"打交道"的方法,然后容器调用这些方法来管理它,让它生成实例,池化,钝化,销毁,再生等.所以这样<br />
<br />
写是错误的。<br />
<br />
62. 问：给定一个字符串5*(5+9)/7怎样计算出结果？<br />
答：<br />
可有两种方法<br />
1。用堆栈完成<br />
2。最简单的方法，不用编程，如果有任何一个数据库的化，用select (5*(5+9)/7) from oneTable<br />
<br />
63. 问：如何实现递交表单内容的加密解密？<br />
答：<br />
如果你用IE目前只能用SSL协议,这一层不要你考虑,否则只你用你自己的工具加密传输,接收后再解密友,至于如何加解,如果要和公认的系统结<br />
<br />
合,就用通用的MD5,RAS等公开算法,如果你只是自己传自己解,你随便按你的想法把数据加上一些东西,取回来按规则减掉这些东西,我敢保证除<br />
<br />
你自己没有任何人能知道解密方法.<br />
<br />
64. 问：为什么Integer.parseInt("+1");会抛出NumberFormatException的异常？<br />
答：因为"+"运行算在JAVA中被重载.系统无法确定你用的是算术加还是字符+。<br />
这一点可以在JAVASCRIPT中更好地理解:<br />
&lt;form name="t"&gt;&lt;input name=s value=1234&gt;&lt;/form&gt;<br />
var a = document.t.s.value+1;<br />
这时a = 12345,因为document.t.s.value作为字符串.但var a = document.t.s.value-1;<br />
a 就是1233,因为系统知道-运算肯定是算术运行.所以把document.t.s.value转换成数字.<br />
<br />
<br />
65. 问：hashCode() 有什么用为什么有时候需要覆盖Object里的hashcode()方法？<br />
答：这就是这个对象的身份证啊,要不如何区分哪个对象。<br />
<br />
66. 问：怎样在tomcat中实现一个定时执行的东东？<br />
答：<br />
在应用程序启动时自动运行。servlet2.3中定义了ServletListener,监听Servlet Con text的启动或则关闭（可在配置文件中配置），启动时<br />
<br />
触发一个守护程序的运行(可以实现java.util.Timer或则 javax.swing.Timer).<br />
<br />
67. 问：程序可以输出自己吗？<br />
答：孔德悖论这个非常有名的法则.就是说任何程序都不可能输出自己.<br />
<br />
68. 问：能够把字符转化成ASCII码？比如将 A 转化成 65？<br />
答：<br />
int a='A';<br />
out.println(a);<br />
<br />
69. 问：如何区分输入的文字中的全角与半角？<br />
答：由于不能分辨出全角和半角字符的值有什么规律,只好把全角符号牧举出来了.<br />
<br />
70. 问：用户注册后的自动发信程序该怎么做？<br />
答：<br />
这种发信程序不考虑性能,因为不可能1秒就有一个人注册,我们说的考虑性能的发信程序是指上百万封信在队列里要不停发送的那种,象你这个<br />
<br />
随便怎么写一个程序都行,没有必要用JAVAMAIL.只要指定一个发信的服务器然后用cocket连它的25口就行了.自己用SOCKET连SMTP的25口发一封<br />
<br />
信就好象两个邻居之间送一样东西,直接递过去得了,用JAVAMAIL,消息机制就是你把这个东西从邮局寄给你的邻居了.&nbsp;&nbsp;<br />
<img src ="http://www.blogjava.net/libin2722/aggbug/158058.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/libin2722/" target="_blank">礼物</a> 2007-11-04 12:59 <a href="http://www.blogjava.net/libin2722/articles/158058.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>提升JSP应用程序的七大绝招 </title><link>http://www.blogjava.net/libin2722/articles/144154.html</link><dc:creator>礼物</dc:creator><author>礼物</author><pubDate>Tue, 11 Sep 2007 02:08:00 GMT</pubDate><guid>http://www.blogjava.net/libin2722/articles/144154.html</guid><wfw:comment>http://www.blogjava.net/libin2722/comments/144154.html</wfw:comment><comments>http://www.blogjava.net/libin2722/articles/144154.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/libin2722/comments/commentRss/144154.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/libin2722/services/trackbacks/144154.html</trackback:ping><description><![CDATA[<strong>处理 SSI 文件时出错</strong><br />
<!-- 提升JSP应用程序的七大绝招 --><!-- google_ad_section_start -->
<div class="wengu_com">提升JSP应用程序的七大绝招<img src="http://www.raqu.com/article/uploadfiles/tr.gif"  alt="" />提升JSP应用程序的七大绝招2006-7-19 23:30:55提升JSP应用程序的七大绝招2006-7-19 23:30:55提升JSP应用程序的七大绝招</div>
&nbsp;&nbsp;&nbsp; 你时常被客户抱怨JSP页面响应速度很慢吗？你想过当客户访问次数剧增时，你的WEB应用能承受日益增加的访问量吗？本文讲述了调整JSP和servlet的一些非常实用的方法，它可使你的servlet和JSP页面响应更快，扩展性更强。而且在用户数增加的情况下，系统负载会呈现出平滑上长的趋势。在本文中，我将通过一些实际例子和配置方法使得你的应用程序的性能有出人意料的提升。其中，某些调优技术是在你的编程工作中实现的。而另一些技术是与应用服务器的配置相关的。在本文中，我们将详细地描述怎样通过调整servlet和JSP页面，来提高你的应用程序的总体性能。在阅读本文之前，假设你有基本的servlet和JSP的知识。<br />
<br />
　　方法一：在servlet的init()方法中缓存数据<br />
<br />
　　当应用服务器初始化servlet实例之后，为客户端请求提供服务之前，它会调用这个servlet的init()方法。在一个servlet的生命周期中，init()方法只会被调用一次。通过在init()方法中缓存一些静态的数据或完成一些只需要执行一次的、耗时的操作，就可大大地提高系统性能。<br />
<br />
　　例如，通过在init()方法中建立一个JDBC连接池是一个最佳例子，假设我们是用jdbc2.0的DataSource接口来取得数据库连接，在通常的情况下，我们需要通过JNDI来取得具体的数据源。我们可以想象在一个具体的应用中，如果每次SQL请求都要执行一次JNDI查询的话，那系统性能将会急剧下降。解决方法是如下代码，它通过缓存DataSource，使得下一次SQL调用时仍然可以继续利用它：<br />
<br />
<br />
<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;public&nbsp;class&nbsp;ControllerServlet&nbsp;extends&nbsp;HttpServlet<br />
{<br />
　private&nbsp;javax.sql.DataSource&nbsp;testDS&nbsp;=&nbsp;null;&nbsp;<br />
　public&nbsp;void&nbsp;init(ServletConfig&nbsp;config)&nbsp;throws&nbsp;ServletException<br />
　{<br />
　　super.init(config);&nbsp;<br />
　　Context&nbsp;ctx&nbsp;=&nbsp;null;<br />
　　try<br />
　　{&nbsp;<br />
　　　ctx&nbsp;=&nbsp;new&nbsp;InitialContext();<br />
　　　testDS&nbsp;=&nbsp;(javax.sql.DataSource)ctx.lookup("jdbc/testDS");<br />
　　}<br />
　　catch(NamingException&nbsp;ne)<br />
　　{<br />
　　　ne.printStackTrace();&nbsp;<br />
　　}<br />
　　catch(Exception&nbsp;e)<br />
　　{<br />
　　　e.printStackTrace();<br />
　　}<br />
　}<br />
<br />
　public&nbsp;javax.sql.DataSource&nbsp;getTestDS()<br />
　{<br />
　　return&nbsp;testDS;<br />
　}<br />
　...<br />
　...&nbsp;<br />
}&nbsp;<br />
<br />
　　方法&nbsp;2:禁止servlet和JSP&nbsp;自动重载(auto-reloading)<br />
<br />
　　Servlet/JSP提供了一个实用的技术，即自动重载技术，它为开发人员提供了一个好的开发环境，当你改变servlet和JSP页面后而不必重启应用服务器。然而，这种技术在产品运行阶段对系统的资源是一个极大的损耗，因为它会给JSP引擎的类装载器(classloader)带来极大的负担。因此关闭自动重载功能对系统性能的提升是一个极大的帮助。<br />
<br />
　　方法&nbsp;3:&nbsp;不要滥用HttpSession&nbsp;<br />
<br />
　　在很多应用中，我们的程序需要保持客户端的状态，以便页面之间可以相互联系。但不幸的是由于HTTP具有天生无状态性，从而无法保存客户端的状态。因此一般的应用服务器都提供了session来保存客户的状态。在JSP应用服务器中，是通过HttpSession对像来实现session的功能的，但在方便的同时，它也给系统带来了不小的负担。因为每当你获得或更新session时，系统者要对它进行费时的序列化操作。你可以通过对HttpSession的以下几种处理方式来提升系统的性能：<br />
<br />
　　?&nbsp;如果没有必要，就应该关闭JSP页面中对HttpSession的缺省设置：&nbsp;如果你没有明确指定的话，每个JSP页面都会缺省地创建一个HttpSession。如果你的JSP中不需要使用session的话，那可以通过如下的JSP页面指示符来禁止它：<br />
<br />
<br />
<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;＜%@&nbsp;page&nbsp;session="false"%＞&nbsp;&nbsp;<br />
<br />
　　?&nbsp;不要在HttpSession中存放大的数据对像：如果你在HttpSession中存放大的数据对像的话，每当对它进行读写时，应用服务器都将对其进行序列化，从而增加了系统的额外负担。你在HttpSession中存放的数据对像越大，那系统的性能就下降得越快。<br />
<br />
　　?&nbsp;当你不需要HttpSession时，尽快地释放它：当你不再需要session时，你可以通过调用HttpSession.invalidate()方法来释放它。<br />
<br />
　　?&nbsp;尽量将session的超时时间设得短一点：在JSP应用服务器中，有一个缺省的session的超时时间。当客户在这个时间之后没有进行任何操作的话，系统会将相关的session自动从内存中释放。超时时间设得越大，系统的性能就会越低，因此最好的方法就是尽量使得它的值保持在一个较低的水平。<br />
<br />
<br />
　　方法&nbsp;4:&nbsp;将页面输出进行压缩<br />
<br />
　　压缩是解决数据冗余的一个好的方法，特别是在网络带宽不够发达的今天。有的浏览器支持gzip(GNU&nbsp;zip)进行来对HTML文件进行压缩，这种方法可以戏剧性地减少HTML文件的下载时间。因此，如果你将servlet或JSP页面生成的HTML页面进行压缩的话，那用户就会觉得页面浏览速度会非常快。但不幸的是，不是所有的浏览器都支持gzip压缩，但你可以通过在你的程序中检查客户的浏览器是否支持它。下面就是关于这种方法实现的一个代码片段：<br />
<br />
<br />
<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;public&nbsp;void&nbsp;doGet(HttpServletRequest&nbsp;request,&nbsp;HttpServletResponse&nbsp;response)<br />
throws&nbsp;IOException,&nbsp;ServletException&nbsp;<br />
{<br />
　OutputStream&nbsp;out&nbsp;=&nbsp;null<br />
　String&nbsp;encoding&nbsp;=&nbsp;request.getHeader("Accept-Encoding");&nbsp;<br />
　if&nbsp;(encoding&nbsp;!=&nbsp;null&nbsp;&amp;&amp;&nbsp;encoding.indexOf("gzip")&nbsp;!=&nbsp;-1)<br />
　{<br />
　　request.setHeader("Content-Encoding"&nbsp;,&nbsp;"gzip");<br />
　　out&nbsp;=&nbsp;new&nbsp;GZIPOutputStream(request.getOutputStream());<br />
　}<br />
　else&nbsp;if&nbsp;(encoding&nbsp;!=&nbsp;null&nbsp;&amp;&amp;&nbsp;encoding.indexOf("compress")&nbsp;!=&nbsp;-1)<br />
　{<br />
　　request.setHeader("Content-Encoding"&nbsp;,&nbsp;"compress");<br />
　　out&nbsp;=&nbsp;new&nbsp;ZIPOutputStream(request.getOutputStream());<br />
　}&nbsp;<br />
　else<br />
　{<br />
　　out&nbsp;=&nbsp;request.getOutputStream();<br />
　}<br />
　...<br />
　...&nbsp;<br />
}&nbsp;&nbsp;<br />
<br />
　　方法&nbsp;5:&nbsp;使用线程池<br />
<br />
　　应用服务器缺省地为每个不同的客户端请求创建一个线程进行处理，并为它们分派service()方法，当service()方法调用完成后，与之相应的线程也随之撤消。由于创建和撤消线程会耗费一定的系统资源，这种缺省模式降低了系统的性能。但所幸的是我们可以通过创建一个线程池来改变这种状况。另外，我们还要为这个线程池设置一个最小线程数和一个最大线程数。在应用服务器启动时，它会创建数量等于最小线程数的一个线程池，当客户有请求时，相应地从池从取出一个线程来进行处理，当处理完成后，再将线程重新放入到池中。如果池中的线程不够地话，系统会自动地增加池中线程的数量，但总量不能超过最大线程数。通过使用线程池，当客户端请求急剧增加时，系统的负载就会呈现的平滑的上升曲线，从而提高的系统的可伸缩性。<br />
<br />
　　方法&nbsp;6:&nbsp;选择正确的页面包含机制<br />
<br />
　　在JSP中有两种方法可以用来包含另一个页面：1、使用include指示符(＜%@&nbsp;includee&nbsp;file=&#8221;test.jsp&#8221;&nbsp;%＞)。2、使用jsp指示符(＜jsp:includee&nbsp;page=&#8221;test.jsp&#8221;&nbsp;flush=&#8221;true&#8221;/＞)。在实际中我发现，如果使用第一种方法的话，可以使得系统性能更高。<br />
<br />
　　方法&nbsp;7:正确地确定javabean的生命周期<br />
<br />
　　JSP的一个强大的地方就是对javabean的支持。通过在JSP页面中使用＜jsp:useBean＞标签，可以将javabean直接插入到一个JSP页面中。它的使用方法如下：<br />
<br />
<br />
<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;＜jsp:useBean&nbsp;id="name"&nbsp;scope="page|request|session|application"&nbsp;class=<br />
"package.className"&nbsp;type="typeName"＞<br />
＜/jsp:useBean＞&nbsp;<br />
<br />
　　其中scope属性指出了这个bean的生命周期。缺省的生命周期为page。如果你没有正确地选择bean的生命周期的话，它将影响系统的性能。<br />
<br />
　　举例来说，如果你只想在一次请求中使用某个bean，但你却将这个bean的生命周期设置成了session，那当这次请求结束后，这个bean将仍然保留在内存中，除非session超时或用户关闭浏览器。这样会耗费一定的内存，并无谓的增加了JVM垃圾收集器的工作量。因此为bean设置正确的生命周期，并在bean的使命结束后尽快地清理它们，会使用系统性能有一个提高。<br />
<br />
　　其它一些有用的方法&nbsp;<br />
<br />
　　?&nbsp;在字符串连接操作中尽量不使用&#8220;＋&#8221;操作符：在java编程中，我们常常使用&#8220;＋&#8221;操作符来将几个字符串连接起来，但你或许从来没有想到过它居然会对系统性能造成影响吧？由于字符串是常量，因此JVM会产生一些临时的对像。你使用的&#8220;＋&#8221;越多，生成的临时对像就越多，这样也会给系统性能带来一些影响。解决的方法是用StringBuffer对像来代替&#8220;＋&#8221;操作符。<br />
<br />
　　?&nbsp;避免使用System.out.println()方法：由于System.out.println()是一种同步调用，即在调用它时，磁盘I/O操作必须等待它的完成，因此我们要尽量避免对它的调用。但我们在调试程序时它又是一个必不可少的方便工具，为了解决这个矛盾，我建议你最好使用Log4j工具(http://Jakarta.apache.org&nbsp;)，它既可以方便调试，而不会产生System.out.println()这样的方法。<br />
<br />
　　?&nbsp;ServletOutputStream&nbsp;与&nbsp;PrintWriter的权衡:使用PrintWriter可能会带来一些小的开销，因为它将所有的原始输出都转换为字符流来输出，因此如果使用它来作为页面输出的话，系统要负担一个转换过程。而使用ServletOutputStream作为页面输出的话就不存在一个问题，但它是以二进制进行输出的。因此在实际应用中要权衡两者的利弊。<br />
<br />
　　总结<br />
<br />
　　本文的目的是通过对servlet和JSP的一些调优技术来极大地提高你的应用程序的性能，并因此提升整个J2EE应用的性能。通过这些调优技术，你可以发现其实并不是某种技术平台（比如J2EE和.NET之争）决定了你的应用程序的性能，重要是你要对这种平台有一个较为深入的了解，这样你才能从根本上对自己的应用程序做一个优化！
 <img src ="http://www.blogjava.net/libin2722/aggbug/144154.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/libin2722/" target="_blank">礼物</a> 2007-09-11 10:08 <a href="http://www.blogjava.net/libin2722/articles/144154.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>