<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="http://feeds.qzone.qq.com/rss.xsl" version="1.0"?>
<rss version="2.0" xmlns:qz="http://qzone.qq.com">
<channel>
<title><![CDATA[木枫]]></title>
<description><![CDATA[木枫]]></description>
<link>http://94164590.qzone.qq.com</link>
<lastBuildDate>Sat, 28 Nov 2009 01:48:34 GMT</lastBuildDate>
<generator>Qzone</generator>
<language>zh-cn</language>
<copyright>Copyright (C), 2005-2008, Tencent Tech. Co., Ltd.</copyright>
<pubDate>Wed, 09 Sep 2009 01:26:54 GMT</pubDate>

<item>
<title><![CDATA[xmlHttp.status]]></title>
<link>http://94164590.qzone.qq.com/blog/1252459614</link>
<description><![CDATA[xmlHttp.status的值（HTTP状态表）0**：未被始化 1**：请求收到，继续处理 2**：操作成功收到，分析、接受 3**：完成此请求必须进一步处理 4**：请求包含一个错误语法或不能完成 5**：服务器执行一个完全有效请求失败 100——客户必须继续发出请求 101——客户要求服务器根据请求转换HTTP协议版本 200——交易成功 201——提示知道新文件的URL 202——接受和处理、但处理未完成 203——返回信息不确定或不完整 204——请求收到，但返回信息为空 205——服务器完成了请求，用户代理必须复位当前已经浏览过的文件 206——服务器已经完成了部分用户的GET请求 300——请求的资源可在多处得到 301——删除请求数据 302——在其他地址发现了请求数据 303——建议客户访问其他URL或访问方式 304——客户端已经执行了GET，但文件未变化 305——请求的资源必须从服务器指定的地址得到 306——前一版本HTTP中使用的代码，现行版本中不再使用 307——申明请求的资源临时性删除 400——错误请求，如语法错误 401——请求授权失败 402——保留有效ChargeTo头响应 403——请求不允许 404——没有发现文件、查询或URl 405——用户在Request-Line字段定义的方法不允许 406——根据用户发送的Accept拖，请求资源不可访问 407——类似401，用户必须首先在代理服务器上得到授权 408——客户端没有在用户指定的饿时间内完成请求 409——对当前资源状态，请求不能完成 410——服务器上不再有此资源且无进一步的参考地址 411——服务器拒绝用户定义的Content-Length属性请求 412——一个或多个请求头字段在当前请求中错误 413——请求的资源大于服务器允许的大小 414——请求的资源URL长于服务器允许的长度 415——请求资源不支持请求项目格式 416——请求中包含Range请求头字段，在当前请求资源范围内没有range指示值，请求也不包含If-Range请求头字段 417——服务器不满足请求Expect头字段指定的期望值，如果是代理服务器，可能是下一级服务器不能满足请求 500——服务器产生内部错误 501——服务器不支持请求的函数 502——服务器暂时不可用，有时是为了防止发生系统过载 503——服务器过载或暂停维修 504——关口过载，服务器使用另一个关口或服务来响应用户，等待时间设定值较长 505——服务器不支持或拒绝支请求头中指定的HTTP版本1xx:信息响应类，表示接收到请求并且继续处理 2xx:处理成功响应类，表示动作被成功接收、理解和接受 3xx:重定向响应类，为了完成指定的动作，必须接受进一步处理 4xx:客户端错误，客户请求包含语法错误或者是不能正确执行 5xx:服务端错误，服务器不能正确执行一个正确的请求 <!--v:3.2--> ]]></description>
<category><![CDATA[Web]]></category>
<author><![CDATA[94164590@qq.com(木枫)]]></author>
<comments>http://94164590.qzone.qq.com/blog/1252459614#comment</comments>
<qz:effect>134218240</qz:effect>
<pubDate>Wed, 09 Sep 2009 01:26:54 GMT</pubDate>
<guid>http://94164590.qzone.qq.com/blog/1252459614</guid>
</item>

<item>
<title><![CDATA[JSP中文编码难题解决方法详解]]></title>
<link>http://94164590.qzone.qq.com/blog/1250150932</link>
<description><![CDATA[最基本的乱码问题 <br>　　这个乱码问题是最简单的乱码问题。一般新会出现。就是页面编码不一致导致的乱码。 <br>　　Html代码： <br>＜%@ page language=&quot;java&quot; pageEncoding=&quot;UTF-8&quot;%＞　 <br>＜%@ page contentType=&quot;text/html;charset=iso8859-1&quot;%＞　 <br>＜html＞　 <br>＜head＞　 <br>＜title＞中文问题＜/title＞　 <br>＜meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;＞　 <br>＜/head＞　 <br>＜/head＞　 <br>＜body＞　 <br>我是个好人　 <br>＜/body＞　 <br>＜/html＞　 　　三个地方的编码 <br>　　第一个地方的编码格式为jsp文件的存储格式。Ecljpse会根据这个编码格式保存文件。并编译jsp文件，包括里面的汉字。 <br>　　第二处编码为解码格式。因为存为UTF-8的文件被解码为iso8859-1，这样如有中文肯定出乱码。也就是必须一致。而第二处所在的这一行，可以没有。缺省也是使用iso8859-1的编码格式。所以如果没有这一行的话，“我是个好人”也会出现乱码。必须一致才可以。 <br>　　第三处编码为控制浏览器的解码方式。如果前面的解码都一致并且无误的话，这个编码格式没有关系。有的网页出现乱码，就是因为浏览器不能确定使用那种编码格式。因为页面有时候会嵌入页面，导致浏览器混淆了编码格式。出现了乱码。 <br>　　表单使用Post方式提交后接收到的乱码问题 <br>　　这个问题也是一个常见的问题。这个乱码也是tomcat的内部编码格式iso8859-1在捣乱，也就是说post提交时，如果没有设置提交的编码格式，则会以iso8859-1方式进行提交，接受的jsp却以utf-8的方式接受。导致乱码。既然这样的原因，下面有几种解决方式，并比较。 <br>　　a. 接受参数时进行编码转换 <br>String str = new String(request.getParameter(&quot;something&quot;).getBytes(&quot;ISO-8859-1&quot;),&quot;utf-8&quot;) ；  <br>　　这样的话，每一个参数都必须这样进行转码。很麻烦。但确实可以拿到汉字。 <br>　　b. 在请求页面上开始处，执行请求的编码代码 <br>request.setCharacterEncoding(&quot;UTF-8&quot;)  <br>　　把提交内容的字符集设为UTF－8。这样的话，接受此参数的页面就不必在转码了。直接使用 <br>String str = request.getParameter(&quot;something&quot;)；  <br>　　即可得到汉字参数。但每页都需要执行这句话。这个方法也就对post提交的有效果，对于get提交和上传文件时的enctype=&quot;multipart/form-data&quot;是无效的。稍后下面单独对这个两个的乱码情况再进行说明。 <br>　　c. 为了避免每页都要写request.setCharacterEncoding(&quot;UTF-8&quot;)，建议使用过滤器对所有jsp进行编码处理。这个网上有很多例子。请大家自己查阅。 <br>　　表单get提交方式的乱码处理方式 <br>　　如果使用get方式提交中文，接受参数的页面也会出现乱码，这个乱码的原因也是tomcat的内部编码格式iso8859-1导致。Tomcat会以get的缺省编码方式iso8859-1对汉字进行编码，编码后追加到url，导致接受页面得到的参数为乱码/、。 <br>　　解决办法： <br>　　a. 使用上例中的第一种方式，对接受到的字符进行解码，再转码。 <br>　　b. Get走的是url提交，而在进入url之前已经进行了iso8859-1的编码处理。要想影响这个编码则需要在server.xml的Connector节点增加useBodyEncodingForURI=&quot;true&quot;属性配置，即可控制tomcat对get方式的汉字编码方式，上面这个属性控制get提交也是用request.setCharacterEncoding(&quot;UTF-8&quot;)所设置的编码格式进行编码。所以自动编码为utf-8，接受页面正常接受就可以了。但我认为真正的编码过程是，tomcat又要根据 <br>＜Connector port=&quot;8080&quot; <br>maxThreads=&quot;150&quot; minSpareThreads=&quot;25&quot; maxSpareThreads=&quot;75&quot; <br>enableLookups=&quot;false&quot; redirectPort=&quot;8443&quot; acceptCount=&quot;100&quot; <br>debug=&quot;0&quot; connectionTimeout=&quot;20000&quot; useBodyEncodingForURI=&quot;true&quot; <br>disableUploadTimeout=&quot;true&quot; URIEncoding=”UTF-8”/＞ 　　里面所设置的URIEncoding=”UTF-8”再进行一次编码，但是由于已经编码为utf-8，再编码也不会有变化了。如果是从url获取编码，接受页面则是根据URIEncoding=”UTF-8”来进行解码的。 <br>　　上传文件时的乱码解决 <br>　　上传文件时，form表单设置的都是enctype=&quot;multipart/form-data&quot;。这种方式以流方式提交文件。如果使用apach的上传组件，会发现有很多乱码想象。这是因为apach的先期commons-fileupload.jar有bug，取出汉字后进行解码，因为这种方式提交，编码又自动使用的是tomcat缺省编码格式iso-8859-1。但出现的乱码问题是：句号，逗号，等特殊符号变成了乱码，汉字如果数量为奇数，则会出现乱码，偶数则解析正常。 <br>　　解决方式： <br>　　下载commons-fileupload-1.1.1.jar 这个版本的jar已经解决了这些bug。 <br>　　但是取出内容时仍然需要对取出的字符进行从iso8859-1到utf-8转码。已经能得到正常所有汉字以及字符。 <br>　　Java代码关于url请求，接受参数的乱码 <br>　　url的编码格式，取决于上面所说的URIEncoding=”UTF-8”。如果设定了这个编码格式，则意味着所有到url的汉字参数，都必须进行编码才可以。否则得到的汉字参数值都是乱码，例如一个链接： <br>Response.sendDerect（“/a.jsp?name=张大维”）；  <br>　　而在a.jsp里面直接使用 <br>String name = request.getParameter（&quot;name&quot;）；  <br>　　得到的就是乱码。因为规定了必须是utf-8才可以，所以，这个转向应该这样写： <br>Response.sendDerect（“/a.jsp?name=URLEncode.encode(“张大维”,”utf-8”)；  <br>　　才可以。 <br>　　如果不设置这个参数URIEncoding=”UTF-8”，会怎样样呢? 不设置则就使用了缺省的编码格式iso8859-1。问题又出来了，第一就是参数值的个数如果是奇数个数，则就可以正常解析，如果使偶数个数，得到最后字符就是乱码。还有就是如果最后一个字符如果是英文，则就能正常解析，但中文的标点符号仍出现乱码。权宜之计，如果您的参数中没有中文标点符号，则可以在参数值最后加一个英文符号来解决乱码问题，得到参数后再去掉这个最后面的符号。也可以凑或使用。 <br>　　脚本代码关于url请求，接受到的参数乱码 <br>　　脚本中也会进行页面转向的控制，也会涉及到附带参数，并在接受页面解析这个参数的情况。如果这个汉字参数不进行URIEncoding=”UTF-8”所指定的编码处理，则接受页面接受到的汉字也是乱码。脚本处理编码比较麻烦，必须有相应的编码脚本对应文件，然后调用脚本中的方法对汉字进行编码即可。 <br>　　关于jsp在MyEclipse中打开的乱码问题 <br>　　对于一个已经存在的项目，Jsp文件的存储格式可能是utf-8。如果新安装的eclipse，则缺省打开使用的编码格式都是iso8859-1。所以导致jsp里面的汉字出现乱码。这个乱码比较容易解决，直接到eclipse3.1的偏好设置里面找到general-〉edidor，设置为您的文件打开编码为utf-8即可。Eclipse会自动重新以新的编码格式打开。汉字即可正常显示。 <br>　　关于html页面在eclipse中打开出现乱码情况 <br>　　由于大部分页面都是由dreamweaver制作，其存储格式跟eclipse的识别有差别导致。一般这种情况，在eclipse中新建一个jsp，直接从dreamweaver复制页面内容粘贴到jsp即可。 <!--v:3.2--> ]]></description>
<category><![CDATA[JSP]]></category>
<author><![CDATA[94164590@qq.com(木枫)]]></author>
<comments>http://94164590.qzone.qq.com/blog/1250150932#comment</comments>
<qz:effect>134218240</qz:effect>
<pubDate>Thu, 13 Aug 2009 08:08:52 GMT</pubDate>
<guid>http://94164590.qzone.qq.com/blog/1250150932</guid>
</item>

<item>
<title><![CDATA[在jsp中实用jspSmartUpload实现上传下载全攻略(二)]]></title>
<link>http://94164590.qzone.qq.com/blog/1250150610</link>
<description><![CDATA[在jsp中实用jspSmartUpload实现上传下载全攻略(二) 7、setDeniedFilesList  <br>作用：用于限制上传那些带有指定扩展名的文件。若有文件扩展名被限制，则上传时组件将抛出异常。  <br>原型：public void setDeniedFilesList(String deniedFilesList)  <br>其中，deniedFilesList为禁止上传的文件扩展名列表，各个扩展名之间以逗号分隔。如果想禁止上传那些没有扩展名的文件，可以用两个逗号来表示。例如：setDeniedFilesList(&quot;exe,bat,,&quot;)将禁止上传带exe和bat扩展名的文件以及没有扩展名的文件。  <br>8、setMaxFileSize  <br>作用：设定每个文件允许上传的最大长度。  <br>原型：public void setMaxFileSize(long maxFileSize)  <br>其中，maxFileSize为为每个文件允许上传的最大长度，当文件超出此长度时，将不被上传。  <br>9、setTotalMaxFileSize  <br>作用：设定允许上传的文件的总长度，用于限制一次性上传的数据量大小。  <br>原型：public void setTotalMaxFileSize(long totalMaxFileSize)  <br>其中，totalMaxFileSize为允许上传的文件的总长度。  <br><span style="font-weight:bold"><wbr />C．下载文件常用的方法</span><wbr />  <br>1、setContentDisposition  <br>作用：将数据追加到MIME文件头的CONTENT-DISPOSITION域。jspSmartUpload组件会在返回下载的信息时自动填写MIME文件头的CONTENT-DISPOSITION域，如果用户需要添加额外信息，请用此方法。  <br>原型：public void setContentDisposition(String contentDisposition)  <br>其中，contentDisposition为要添加的数据。如果contentDisposition为null，则组件将自动添加&quot;attachment;&quot;，以表明将下载的文件作为附件，结果是IE浏览器将会提示另存文件，而不是自动打开这个文件（IE浏览器一般根据下载的文件扩展名决定执行什么操作，扩展名为doc的将用word程序打开，扩展名为pdf的将用acrobat程序打开，等等）。  <br>2、downloadFile  <br>作用：下载文件。  <br>原型：共有以下三个原型可用，第一个最常用，后两个用于特殊情况下的文件下载（如更改内容类型，更改另存的文件名）。  <br>① public void downloadFile(String sourceFilePathName)  <br>其中，sourceFilePathName为要下载的文件名（带目录的文件全名）  <br>② public void downloadFile(String sourceFilePathName,String contentType)  <br>其中，sourceFilePathName为要下载的文件名（带目录的文件全名）,contentType为内容类型（MIME格式的文件类型信息，可被浏览器识别）。  <br>③ public void downloadFile(String sourceFilePathName,String contentType,String destFileName)  <br>其中，sourceFilePathName为要下载的文件名（带目录的文件全名）,contentType为内容类型（MIME格式的文件类型信息，可被浏览器识别）,destFileName为下载后默认的另存文件名。  <br><span style="font-weight:bold"><wbr />三、文件上传篇</span><wbr />  <br> <br><span style="font-weight:bold"><wbr />㈠ 表单要求</span><wbr />  <br> <br>对于上传文件的FORM表单，有两个要求：  <br> <br>1、METHOD应用POST，即METHOD=&quot;POST&quot;。  <br> <br>2、增加属性：ENCTYPE=&quot;multipart/form-data&quot;  <br> <br>下面是一个用于上传文件的FORM表单的例子： &lt;FORM METHOD=&quot;POST&quot; ENCTYPE=&quot;multipart/form-data&quot; ACTION=&quot;/jspSmartUpload/upload.jsp&quot;&gt; <br>    &lt;INPUT TYPE=&quot;FILE&quot; &gt; <br>    &lt;INPUT TYPE=&quot;SUBMIT&quot;&gt; <br>    &lt;/FORM&gt;<span style="font-weight:bold"><wbr />㈡ 上传的例子</span><wbr />  <br><span style="font-weight:bold"><wbr />1、上传页面upload.html</span><wbr />  <br>本页面提供表单，让用户选择要上传的文件，点击&quot;上传&quot;按钮执行上传操作。  <br>页面<a href="http://code.knowsky.com/" target="_blank"><span style="color:#4d3002;line-height:1.8em;">源码</span><wbr /></a><wbr />如下：  <br>  <br>&lt;!-- <br>    文件名：upload.html <br>--&gt; <br>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;&gt; <br>&lt;html&gt; <br>&lt;head&gt; <br>&lt;title&gt;文件上传&lt;/title&gt; <br>&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=gb2312&quot;&gt; <br>&lt;/head&gt; <br> <br>&lt;body&gt; <br>&lt;p&gt;&amp;nbsp;&lt;/p&gt; <br>&lt;p align=&quot;center&quot;&gt;上传文件选择&lt;/p&gt; <br>&lt;FORM METHOD=&quot;POST&quot; ACTION=&quot;jsp/do_upload.jsp&quot; <br>ENCTYPE=&quot;multipart/form-data&quot;&gt; <br>&lt;input type=&quot;hidden&quot; value=&quot;good&quot;&gt; <br>  &lt;table width=&quot;75%&quot; border=&quot;1&quot; align=&quot;center&quot;&gt; <br>    &lt;tr&gt;  <br>      &lt;td&gt;&lt;div align=&quot;center&quot;&gt;1、  <br>          &lt;input type=&quot;FILE&quot; size=&quot;30&quot;&gt; <br>        &lt;/div&gt;&lt;/td&gt; <br>    &lt;/tr&gt; <br>    &lt;tr&gt;  <br>      &lt;td&gt;&lt;div align=&quot;center&quot;&gt;2、  <br>          &lt;input type=&quot;FILE&quot; size=&quot;30&quot;&gt; <br>        &lt;/div&gt;&lt;/td&gt; <br>    &lt;/tr&gt; <br>    &lt;tr&gt;  <br>      &lt;td&gt;&lt;div align=&quot;center&quot;&gt;3、  <br>          &lt;input type=&quot;FILE&quot; size=&quot;30&quot;&gt; <br>        &lt;/div&gt;&lt;/td&gt; <br>    &lt;/tr&gt; <br>    &lt;tr&gt;  <br>      &lt;td&gt;&lt;div align=&quot;center&quot;&gt;4、  <br>          &lt;input type=&quot;FILE&quot; size=&quot;30&quot;&gt; <br>        &lt;/div&gt;&lt;/td&gt; <br>    &lt;/tr&gt; <br>    &lt;tr&gt;  <br>      &lt;td&gt;&lt;div align=&quot;center&quot;&gt; <br>          &lt;input type=&quot;submit&quot; value=&quot;上传它！&quot;&gt; <br>        &lt;/div&gt;&lt;/td&gt; <br>    &lt;/tr&gt; <br>  &lt;/table&gt; <br>&lt;/FORM&gt; <br>&lt;/body&gt; <br>&lt;/html&gt;<span style="font-weight:bold"><wbr />2、上传处理页面do_upload.jsp</span><wbr />  <br> <br>本页面执行文件上传操作。页面源码中详细介绍了上传方法的用法，在此不赘述了。  <br> <br>页面源码如下： &lt;%-- <br>文件名：do_upload.jsp <br>--%&gt; <br>&lt;%@ page contentType=&quot;text/html; charset=gb2312&quot; language=&quot;java&quot;  <br>import=&quot;java.util.*,com.jspsmart.upload.*&quot; errorPage=&quot;&quot; %&gt; <br>&lt;html&gt; <br>&lt;head&gt; <br>&lt;title&gt;文件上传处理页面&lt;/title&gt; <br>&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=gb2312&quot;&gt; <br>&lt;/head&gt; <br> <br>&lt;body&gt; <br>&lt;% <br>// 新建一个SmartUpload对象 <br>SmartUpload su = new SmartUpload(); <br>// 上传初始化 <br>su.initialize(pageContext); <br>// 设定上传限制 <br>// 1.限制每个上传文件的最大长度。 <br>// su.setMaxFileSize(10000); <br>// 2.限制总上传数据的长度。 <br>// su.setTotalMaxFileSize(20000); <br>// 3.设定允许上传的文件（通过扩展名限制）,仅允许doc,txt文件。 <br>// su.setAllowedFilesList(&quot;doc,txt&quot;); <br>// 4.设定禁止上传的文件（通过扩展名限制）,禁止上传带有exe,bat, <br>jsp,htm,html扩展名的文件和没有扩展名的文件。 <br>// su.setDeniedFilesList(&quot;exe,bat,jsp,htm,html,,&quot;); <br>// 上传文件 <br>su.upload(); <br>// 将上传文件全部保存到指定目录 <br>int count = su.save(&quot;/upload&quot;); <br>out.println(count+&quot;个文件上传成功！&lt;br&gt;&quot;); <br> <br>// 利用Request对象获取参数之值 <br>out.println(&quot;TEST=&quot;+su.getRequest().getParameter(&quot;TEST&quot;) <br>+&quot;&lt;BR&gt;&lt;BR&gt;&quot;); <br> <br>// 逐一提取上传文件信息，同时可保存文件。 <br>for (int i=0;i&lt;su.getFiles().getCount();i++) <br>{ <br>com.jspsmart.upload.File file = su.getFiles().getFile(i); <br> <br>// 若文件不存在则继续 <br>if (file.isMissing()) continue; <br> <br>// 显示当前文件信息 <br>out.println(&quot;&lt;TABLE BORDER=1&gt;&quot;); <br>out.println(&quot;&lt;TR&gt;&lt;TD&gt;表单项名（FieldName）&lt;/TD&gt;&lt;TD&gt;&quot; <br>+ file.getFieldName() + &quot;&lt;/TD&gt;&lt;/TR&gt;&quot;); <br>out.println(&quot;&lt;TR&gt;&lt;TD&gt;文件长度（Size）&lt;/TD&gt;&lt;TD&gt;&quot; +  <br>file.getSize() + &quot;&lt;/TD&gt;&lt;/TR&gt;&quot;); <br>out.println(&quot;&lt;TR&gt;&lt;TD&gt;文件名（FileName）&lt;/TD&gt;&lt;TD&gt;&quot;  <br>+ file.getFileName() + &quot;&lt;/TD&gt;&lt;/TR&gt;&quot;); <br>out.println(&quot;&lt;TR&gt;&lt;TD&gt;文件扩展名（FileExt）&lt;/TD&gt;&lt;TD&gt;&quot;  <br>+ file.getFileExt() + &quot;&lt;/TD&gt;&lt;/TR&gt;&quot;); <br>out.println(&quot;&lt;TR&gt;&lt;TD&gt;文件全名（FilePathName）&lt;/TD&gt;&lt;TD&gt;&quot; <br>+ file.getFilePathName() + &quot;&lt;/TD&gt;&lt;/TR&gt;&quot;); <br>out.println(&quot;&lt;/TABLE&gt;&lt;BR&gt;&quot;); <br> <br>// 将文件另存 <br>// file.saveAs(&quot;/upload/&quot; + myFile.getFileName()); <br>// 另存到以WEB应用程序的根目录为文件根目录的目录下 <br>// file.saveAs(&quot;/upload/&quot; + myFile.getFileName(),  <br>su.SAVE_VIRTUAL); <br>// 另存到操作系统的根目录为文件根目录的目录下 <br>// file.saveAs(&quot;c:\\temp\\&quot; + myFile.getFileName(),  <br>su.SAVE_PHYSICAL); <br> <br>} <br>%&gt; <br>&lt;/body&gt; <br>&lt;/html&gt;<span style="font-weight:bold"><wbr />四、文件下载篇</span><wbr />  <br> <br><span style="font-weight:bold"><wbr />1、下载链接页面download.html</span><wbr />  <br> <br>页面源码如下：&lt;!-- <br>文件名：download.html <br>--&gt; <br>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;&gt; <br>&lt;html&gt; <br>&lt;head&gt; <br>&lt;title&gt;下载&lt;/title&gt; <br>&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=gb2312&quot;&gt; <br>&lt;/head&gt; <br>&lt;body&gt; <br>&lt;a href=&quot;jsp/do_download.jsp&quot;&gt;点击下载&lt;/a&gt;<span style="font-weight:bold"><wbr />&lt;/body&gt; <br>&lt;/html&gt; <br><span style="font-weight:bold"><wbr />2、下载处理页面do_download.jsp</span><wbr /> do_download.jsp展示了如何利用jspSmartUpload组件来下载文件，从下面的源码中就可以看到，下载何其简单。  <br> <br>源码如下： &lt;%@ page contentType=&quot;text/html;charset=gb2312&quot;  <br>import=&quot;com.jspsmart.upload.*&quot; %&gt;&lt;% <br>// 新建一个SmartUpload对象 <br>SmartUpload su = new SmartUpload(); <br>// 初始化 <br>su.initialize(pageContext); <br>// 设定contentDisposition为null以禁止浏览器自动打开文件， <br>//保证点击链接后是下载文件。若不设定，则下载的文件扩展名为 <br>//doc时，浏览器将自动用word打开它。扩展名为pdf时， <br>//浏览器将用acrobat打开。 <br>su.setContentDisposition(null); <br>// 下载文件 <br>su.downloadFile(&quot;/upload/如何赚取我的第一桶金.doc&quot;); <br>%&gt;注意，执行下载的页面，在Java脚本范围外（即&lt;% ... %&gt;之外），不要包含HTML代码、空格、回车或换行等字符，有的话将不能正确下载。不信的话，可以在上述源码中%&gt;&lt;%之间加入一个换行符，再下载一下，保证出错。因为它影响了返回给浏览器的数据流，导致解析出错。  <br> <br><span style="font-weight:bold"><wbr />3、如何下载中文文件</span><wbr />  <br> <br>jspSmartUpload虽然能下载文件，但对中文支持不足。若下载的文件名中有汉字，则浏览器在提示另存的文件名时，显示的是一堆乱码，很扫人兴。上面的例子就是这样。（这个问题也是众多下载组件所存在的问题，很少有人解决，搜索不到相关资料，可叹！）  <br> <br>为了给jspSmartUpload组件增加下载中文文件的支持，我对该组件进行了研究，发现对返回给浏览器的另存文件名进行UTF-8编码后，浏览器便能正确显示中文名字了。这是一个令人高兴的发现。于是我对jspSmartUpload组件的SmartUpload类做了升级处理，增加了toUtf8String这个方法，改动部分源码如下： public void downloadFile(String s, String s1, String s2, int i) <br>throws ServletException, IOException, SmartUploadException <br>    { <br>if(s == null) <br>    throw new IllegalArgumentException(&quot;File '&quot; + s + <br>    &quot;' not found (1040).&quot;); <br>if(s.equals(&quot;&quot;)) <br>    throw new IllegalArgumentException(&quot;File '&quot; + s + <br>    &quot;' not found (1040).&quot;); <br>if(!isVirtual(s) &amp;&amp; m_denyPhysicalPath) <br>    throw new SecurityException(&quot;Physical path is <br>    denied (1035).&quot;); <br>if(isVirtual(s)) <br>    s = m_application.getRealPath(s); <br>java.io.File file = new java.io.File(s); <br>FileInputStream fileinputstream = new FileInputStream(file); <br>long l = file.length(); <br>boolean flag = false; <br>int k = 0; <br>byte abyte0[] = new byte<span style="font-style:italic"><wbr />; <br>if(s1 == null) <br>    m_response.setContentType(&quot;application/x-msdownload&quot;); <br>else <br>if(s1.length() == 0) <br>    m_response.setContentType(&quot;application/x-msdownload&quot;); <br>else <br>    m_response.setContentType(s1); <br>m_response.setContentLength((int)l); <br>m_contentDisposition = m_contentDisposition != null ? <br>m_contentDis&quot;attachment;&quot;; <br>if(s2 == null) <br>    m_response.setHeader(&quot;Content-Disposition&quot;,  <br>    m_contentDisposition + &quot; filename=&quot; +  <br>    toUtf8String(getFileName(s))); <br>else <br>if(s2.length() == 0) <br>    m_response.setHeader(&quot;Content-Disposition&quot;,  <br>    m_contentDisposition); <br>else <br>    m_response.setHeader(&quot;Content-Disposition&quot;,  <br>    m_contentDisposition + &quot; filename=&quot; + toUtf8String(s2)); <br>while((long)k &lt; l) <br>{ <br>    int j = fileinputstream.read(abyte0, 0, i); <br>    k += j; <br>    m_response.getOutputStream().write(abyte0, 0, j); <br>} <br>fileinputstream.close(); <br>    } <br> <br>    /** <br>     * 将文件名中的汉字转为UTF8编码的串,以便下载时能正确显示另存的文件名. <br>     * @param s 原文件名 <br>     * @return 重新编码后的文件名 <br>     */ <br>    public static String toUtf8String(String s) { <br>StringBuffer sb = new StringBuffer(); <br>for (int i=0;i&lt;s.length();i++) { <br>    char c = s.charAt(i); <br>    if (c &gt;= 0 &amp;&amp; c &lt;= 255) { <br>sb.append(c); <br>    } else { <br>byte[] b; <br>try { <br>    b = Character.toString(c).getBytes(&quot;utf-8&quot;); <br>} catch (Exception ex) { <br>    System.out.println(ex); <br>    b = new byte[0]; <br>} <br>for (int j = 0; j &lt; b.length; j++) { <br>    int k = b[j]; <br>    if (k &lt; 0) k += 256; <br>    sb.append(&quot;%&quot; + Integer.toHexString(k). <br>    toUpperCase()); <br>} <br>    } <br>} <br>return sb.toString(); <br>} <br>注意源码中粗体部分，原jspSmartUpload组件对返回的文件未作任何处理，现在做了编码的转换工作，将文件名转换为UTF-8形式的编码形式。UTF-8编码对英文未作任何处理，对中文则需要转换为%XX的形式。toUtf8String方法中，直接利用Java语言提供的编码转换方法获得汉字字符的UTF-8编码，之后将其转换为%XX的形式。  <br> <br>将源码编译后打包成jspSmartUpload.jar，拷贝到Tomcat的shared/lib目录下（可为所有WEB应用程序所共享），然后重启Tomcat服务器就可以正常下载含有中文名字的文件了。另，toUtf8String方法也可用于转换含有中文的超级链接，以保证链接的有效，因为有的WEB服务器不支持中文链接。  <br> <br>小结：jspSmartUpload组件是应用JSP进行B/S程序开发过程中经常使用的上传下载组件，它使用简单，方便。现在我又为其加上了下载中文名字的文件的支持，真个是如虎添翼，必将赢得更多开发者的青睐。 <!--v:3.2--> ]]></description>
<category><![CDATA[JSP]]></category>
<author><![CDATA[94164590@qq.com(木枫)]]></author>
<comments>http://94164590.qzone.qq.com/blog/1250150610#comment</comments>
<qz:effect>134218240</qz:effect>
<pubDate>Thu, 13 Aug 2009 08:03:30 GMT</pubDate>
<guid>http://94164590.qzone.qq.com/blog/1250150610</guid>
</item>

<item>
<title><![CDATA[在jsp中实用jspSmartUpload实现上传下载全攻略(一)]]></title>
<link>http://94164590.qzone.qq.com/blog/1250150486</link>
<description><![CDATA[在jsp中实用jspSmartUpload实现上传下载全攻略(一) <span style="font-weight:bold"><wbr />一、安装篇</span><wbr />  <br>　　jspSmartUpload是由www.jspsmart.com网站开发的一个可免费使用的全功能的文件上传下载组件，适于嵌入执行上传下载操作的JSP文件中。该组件有以下几个特点：  <br>1、使用简单。在JSP文件中仅仅书写三五行JAVA代码就可以搞定文件的上传或下载，方便。  <br>2、能全程控制上传。利用jspSmartUpload组件提供的对象及其操作方法，可以获得全部上传文件的信息（包括文件名，大小，类型，扩展名，文件数据等），方便存取。  <br>3、能对上传的文件在大小、类型等方面做出限制。如此可以滤掉不符合要求的文件。  <br>4、下载灵活。仅写两行代码，就能把Web服务器变成文件服务器。不管文件在Web服务器的目录下或在其它任何目录下，都可以利用jspSmartUpload进行下载。  <br>5、能将文件上传到<a href="http://www.knowsky.com/sql.asp" target="_blank"><span style="color:#4d3002;line-height:1.8em;">数据库</span><wbr /></a><wbr />中，也能将数据库中的数据下载下来。这种功能针对的是MYSQL数据库，因为不具有通用性，所以本文不准备举例介绍这种用法。  <br>　　jspSmartUpload组件可以从www.jspsmart.com网站上自由下载，压缩包的名字是jspSmartUpload.zip。下载后，用WinZip或<a href="http://www.knowsky.com/article.asp?typeid=66" target="_blank"><span style="color:#4d3002;line-height:1.8em;">WinRAR</span><wbr /></a><wbr />将其解压到Tomcat的webapps目录下（本文以Tomcat服务器为例进行介绍）。解压后，将webapps/jspsmartupload目录下的子目录Web-inf名字改为全大写的WEB-INF，这样一改jspSmartUpload类才能使用。因为Tomcat对文件名大小写敏感，它要求Web应用程序相关的类所在目录为WEB-INF，且必须是大写。接着重新启动Tomcat，这样就可以在JSP文件中使用jspSmartUpload组件了。  <br>　　注意，按上述方法安装后，只有webapps/jspsmartupload目录下的程序可以使用jspSmartUpload组件，如果想让Tomcat服务器的所有Web应用程序都能用它，必须做如下工作：  <br>1．进入命令行状态，将目录切换到Tomcat的webapps/jspsmartupload/WEB-INF目录下。  <br>2．运行JAR打包命令：jar cvf jspSmartUpload.jar com  <br>（也可以打开资源管理器，切换到当前目录，用WinZip将com目录下的所有文件压缩成jspSmartUpload.zip，然后将jspSmartUpload.zip换名为jspSmartUpload.jar文件即可。）  <br>3．将jspSmartUpload.jar拷贝到Tomcat的shared/lib目录下。  <br><span style="font-weight:bold"><wbr />二、相关类说明篇</span><wbr />  <br><span style="font-weight:bold"><wbr />㈠ File类</span><wbr />  <br>　　这个类包装了一个上传文件的所有信息。通过它，可以得到上传文件的文件名、文件大小、扩展名、文件数据等信息。  <br>　　File类主要提供以下方法：  <br>1、saveAs作用：将文件换名另存。  <br>原型：  <br>public void saveAs(java.lang.String destFilePathName)  <br>或  <br>public void saveAs(java.lang.String destFilePathName, int optionSaveAs)  <br>其中，destFilePathName是另存的文件名，optionSaveAs是另存的选项，该选项有三个值，分别是SAVEAS_PHYSICAL,SAVEAS_VIRTUAL，SAVEAS_AUTO。SAVEAS_PHYSICAL表明以<a href="http://www.knowsky.com/system.asp" target="_blank"><span style="color:#4d3002;line-height:1.8em;">操作系统</span><wbr /></a><wbr />的根目录为文件根目录另存文件，SAVEAS_VIRTUAL表明以Web应用程序的根目录为文件根目录另存文件，SAVEAS_AUTO则表示让组件决定，当Web应用程序的根目录存在另存文件的目录时，它会选择SAVEAS_VIRTUAL，否则会选择SAVEAS_PHYSICAL。  <br>例如，saveAs(&quot;/upload/sample.zip&quot;,SAVEAS_PHYSICAL)执行后若Web服务器安装在C盘，则另存的文件名实际是c:\upload\sample.zip。而saveAs(&quot;/upload/sample.zip&quot;,SAVEAS_VIRTUAL)执行后若Web应用程序的根目录是webapps/jspsmartupload，则另存的文件名实际是webapps/jspsmartupload/upload/sample.zip。saveAs(&quot;/upload/sample.zip&quot;,SAVEAS_AUTO)执行时若Web应用程序根目录下存在upload目录，则其效果同saveAs(&quot;/upload/sample.zip&quot;,SAVEAS_VIRTUAL)，否则同saveAs(&quot;/upload/sample.zip&quot;,SAVEAS_PHYSICAL)。  <br>建议：对于Web程序的开发来说，最好使用SAVEAS_VIRTUAL，以便移植。  <br>2、isMissing  <br>作用：这个方法用于判断用户是否选择了文件，也即对应的表单项是否有值。选择了文件时，它返回false。未选文件时，它返回true。  <br>原型：public boolean isMissing()  <br>3、getFieldName  <br>作用：取HTML表单中对应于此上传文件的表单项的名字。  <br>原型：public String getFieldName()  <br>4、getFileName  <br>作用：取文件名（不含目录信息）  <br>原型：public String getFileName()  <br>5、getFilePathName  <br>作用：取文件全名（带目录）  <br>原型：public String getFilePathName  <br>6、getFileExt  <br>作用：取文件扩展名（后缀）  <br>原型：public String getFileExt()  <br>7、getSize  <br>作用：取文件长度（以字节计）  <br>原型：public int getSize()  <br>8、getBinaryData  <br>作用：取文件数据中指定位移处的一个字节，用于检测文件等处理。  <br>原型：public byte getBinaryData(int index)。其中，index表示位移，其值在0到getSize()-1之间。  <br><span style="font-weight:bold"><wbr />㈡ Files类</span><wbr />  <br>　　这个类表示所有上传文件的集合，通过它可以得到上传文件的数目、大小等信息。有以下方法：  <br>1、getCount  <br>作用：取得上传文件的数目。  <br>原型：public int getCount()  <br>2、getFile  <br>作用：取得指定位移处的文件对象File（这是com.jspsmart.upload.File，不是java.io.File，注意区分）。  <br>原型：public File getFile(int index)。其中，index为指定位移，其值在0到getCount()-1之间。  <br>3、getSize  <br>作用：取得上传文件的总长度，可用于限制一次性上传的数据量大小。  <br>原型：public long getSize()  <br>4、getCollection  <br>作用：将所有上传文件对象以Collection的形式返回，以便其它应用程序引用，浏览上传文件信息。  <br>原型：public Collection getCollection()  <br>5、getEnumeration  <br>作用：将所有上传文件对象以Enumeration（枚举）的形式返回，以便其它应用程序浏览上传文件信息。  <br>原型：public Enumeration getEnumeration()  <br><span style="font-weight:bold"><wbr />㈢ Request类</span><wbr />  <br>　　这个类的功能等同于JSP内置的对象request。只所以提供这个类，是因为对于文件上传表单，通过request对象无法获得表单项的值，必须通过jspSmartUpload组件提供的Request对象来获取。该类提供如下方法：  <br>1、getParameter  <br>作用：获取指定参数之值。当参数不存在时，返回值为null。  <br>原型：public String getParameter(String name)。其中，name为参数的名字。  <br>2、getParameterValues  <br>作用：当一个参数可以有多个值时，用此方法来取其值。它返回的是一个字符串数组。当参数不存在时，返回值为null。  <br>原型：public String[] getParameterValues(String name)。其中，name为参数的名字。  <br>3、getParameterNames  <br>作用：取得Request对象中所有参数的名字，用于遍历所有参数。它返回的是一个枚举型的对象。  <br>原型：public Enumeration getParameterNames()  <br><span style="font-weight:bold"><wbr />㈣ SmartUpload类</span><wbr />这个类完成上传下载工作。  <br><span style="font-weight:bold"><wbr />A．上传与下载共用的方法：</span><wbr />  <br>只有一个：initialize。  <br>作用：执行上传下载的初始化工作，必须第一个执行。  <br>原型：有多个，主要使用下面这个：  <br>public final void initialize(javax.servlet.jsp.PageContext pageContext)  <br>其中，pageContext为JSP页面内置对象（页面上下文）。  <br><span style="font-weight:bold"><wbr />B．上传文件使用的方法：</span><wbr />  <br>1、upload  <br>作用：上传文件数据。对于上传操作，第一步执行initialize方法，第二步就要执行这个方法。  <br>原型：public void upload()  <br>2、save  <br>作用：将全部上传文件保存到指定目录下，并返回保存的文件个数。  <br>原型：public int save(String destPathName)  <br>和public int save(String destPathName,int option)  <br>其中，destPathName为文件保存目录，option为保存选项，它有三个值，分别是SAVE_PHYSICAL,SAVE_VIRTUAL和SAVE_AUTO。（同File类的saveAs方法的选项之值类似）SAVE_PHYSICAL指示组件将文件保存到以操作系统根目录为文件根目录的目录下，SAVE_VIRTUAL指示组件将文件保存到以Web应用程序根目录为文件根目录的目录下，而SAVE_AUTO则表示由组件自动选择。  <br>注：save(destPathName)作用等同于save(destPathName,SAVE_AUTO)。  <br>3、getSize  <br>作用：取上传文件数据的总长度  <br>原型：public int getSize()  <br>4、getFiles  <br>作用：取全部上传文件，以Files对象形式返回，可以利用Files类的操作方法来获得上传文件的数目等信息。  <br>原型：public Files getFiles()  <br>5、getRequest  <br>作用：取得Request对象，以便由此对象获得上传表单参数之值。  <br>原型：public Request getRequest()  <br>6、setAllowedFilesList  <br>作用：设定允许上传带有指定扩展名的文件，当上传过程中有文件名不允许时，组件将抛出异常。  <br>原型：public void setAllowedFilesList(String allowedFilesList)  <br>其中，allowedFilesList为允许上传的文件扩展名列表，各个扩展名之间以逗号分隔。如果想允许上传那些没有扩展名的文件，可以用两个逗号表示。例如：setAllowedFilesList(&quot;doc,txt,,&quot;)将允许上传带doc和txt扩展名的文件以及没有扩展名的文件 <!--v:3.2--> ]]></description>
<category><![CDATA[JSP]]></category>
<author><![CDATA[94164590@qq.com(木枫)]]></author>
<comments>http://94164590.qzone.qq.com/blog/1250150486#comment</comments>
<qz:effect>134218240</qz:effect>
<pubDate>Thu, 13 Aug 2009 08:01:26 GMT</pubDate>
<guid>http://94164590.qzone.qq.com/blog/1250150486</guid>
</item>

<item>
<title><![CDATA[jsp页面跳转5种方式的比较]]></title>
<link>http://94164590.qzone.qq.com/blog/1250150206</link>
<description><![CDATA[使用JSP大约有下列三种跳转方式： <br>1. response.sendRedirect(); <br>2. response.setHeader(&quot;Location&quot;,&quot;&quot;); <br>3. &lt;jsp:forward page=&quot;&quot; /&gt; 经过试验得到下面的一些规则： <br>一. response.sendRedirect() <br>此语句前不允许有out.flush()，如果有，会有异常： <br>java.lang.IllegalStateException: Can't sendRedirect() after data has committed to the client. <br> at com.caucho.server.connection.AbstractHttpResponse.sendRedirect(AbstractHttpResponse.java:558) <br>... <br>跳转后浏览器地址栏变化 <br>如果要跳到不同主机下，跳转后，此语句后面的语句会继续执行，如同新开了线程，但是对response的操作已经无意义了； <br>如果要跳到相同主机下，此语句后面的语句执行完成后才会跳转； <br>二. response.setHeader(&quot;Location&quot;,&quot;&quot;)此语句前不允许有out.flush()，如果有，页面不会跳转。 <br>跳转后浏览器地址栏变化 <br>此语句后面的语句执行完成后才会跳转 <br>三. &lt;jsp:forward page=&quot;&quot; /&gt; 此语句前不允许有out.flush()，如果有，会有异常： <br>java.lang.IllegalStateException: forward() not allowed after buffer has committed. <br> at com.caucho.server.webapp.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:134) <br> at com.caucho.server.webapp.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:101) <br> at com.caucho.jsp.PageContextImpl.forward(PageContextImpl.java:836) <br> ... <br>跳转后浏览器地址栏不变，但是只能跳到当前主机下 <br>此语句后面的语句执行完成后才会跳转  <br>  <br>  <br><span style="font-weight:bold"><wbr /><span style="color:#ff9900;font-size:24px;line-height:1.8em;">jsp页面跳转5种方式的比较</span><wbr /></span><wbr /> <br>1. RequestDispatcher.forward() <br>　　是在服务器端起作用,当使用forward()时,Servlet engine传递HTTP请求从当前的Servlet or JSP到另外一个Servlet,JSP 或普通HTML文件,也即你的form提交至a.jsp,在a.jsp用到了forward()重定向至b.jsp,此时form提交的所有信息在 b.jsp都可以获得,参数自动传递. 但forward()无法重定向至有frame的jsp文件,可以重定向至有frame的html文件,同时forward()无法在后面带参数传递,比如servlet?name=frank,这样不行,可以程序内通过response.setAttribute(&quot;name&quot;,name)来传至下一个页面。 <br>　　重定向后浏览器地址栏URL不变。 <br>　　例：在servlet中进行重定向 <br>public void doPost(HttpServletRequest request,HttpServletResponse response) <br>throws ServletException,IOException <br>{ <br>　 response.setContentType(&quot;text/html; charset=gb2312&quot;); <br>　 ServletContext sc = getServletContext(); <br>　 RequestDispatcher rd = null; <br>　 rd = sc.getRequestDispatcher(&quot;/index.jsp&quot;); //定向的页面 <br>　 rd.forward(request, response); <br>} 　　通常在servlet中使用，不在jsp中使用。 <br>　　2. response.sendRedirect() <br>　　是在用户的浏览器端工作,sendRedirect()可以带参数传递,比如servlet?name=frank传至下个页面,同时它可以重定向至不同的主机上,sendRedirect()可以重定向有frame.的jsp文件. <br>　　重定向后在浏览器地址栏上会出现重定向页面的URL <br>　　例：在servlet中重定向 <br>public void doPost(HttpServletRequest request,HttpServletResponse response) <br>throws ServletException,IOException <br>{ <br>　 response.setContentType(&quot;text/html; charset=gb2312&quot;); <br>　 response.sendRedirect(&quot;/index.jsp&quot;); <br>}　　由于response是jsp页面中的隐含对象，故在jsp页面中可以用response.sendRedirect()直接实现重定位。 <br>　　注意： <br>　　(1) 使用response.sendRedirect时，前面不能有HTML输出； <br>　　这并不是绝对的，不能有HTML输出其实是指不能有HTML被送到了浏览器。事实上现在的server都有cache机制，一般在8K（我是说 JSP　SERVER），这就意味着，除非你关闭了cache，或者你使用了out.flush()强制刷新，那么在使用sendRedirect之前，有少量的HTML输出也是允许的。 <br>　　(2) response.sendRedirect之后，应该紧跟一句return。 <br>　　我们已经知道response.sendRedirect是通过浏览器来做转向的，所以只有在页面处理完成后，才会有实际的动作。既然你已经要做转向了，那么后的输出还的意义呢？而且有可能会因为后面的输出导致转向失败。 <br>　　比较： <br>　　(1) Dispatcher.forward()是容器中控制权的转向，在客户端浏览器地址栏中不会显示出转向后的地址； <br>　　(2) response.sendRedirect()则是完全的跳转，浏览器将会得到跳转的地址，并重新发送请求链接。这样，从浏览器的地址栏中可以看到跳转后的链接地址。 <br>　　前者更加高效，在前者可以满足需要时，尽量使用RequestDispatcher.forward()方法。 <br>　　注：在有些情况下，比如，需要跳转到一个其它服务器上的资源，则必须使用HttpServletResponse.sendRequest()方法。 <br>　　3. ＜jsp:forward page=&quot;&quot; /＞ <br>　　它的底层部分是由RequestDispatcher来实现的，因此它带有RequestDispatcher.forward()方法的印记。 <br>　　如果在之前有很多输出,前面的输出已使缓冲区满,将自动输出到客户端,那么该语句将不起作用,这一点应该特别注意。  <br>　　另外要注意：它不能改变浏览器地址，刷新的话会导致重复提交 <br>　　4. 修改HTTP header的Location属性来重定向 <br>　　通过设置直接修改地址栏来实现页面的重定向。 <br>　　jsp文件代码如下： <br>＜% <br>　response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); <br>　String newLocn = &quot;/newpath/jsa.jsp&quot;; <br>　response.setHeader(&quot;Location&quot;,newLocn); <br>%＞ <br>　　5. JSP中实现在某页面停留若干秒后,自动重定向到另一页面 <br>　　在html文件中，下面的代码： <br>＜meta http-equiv=&quot;refresh&quot; content=&quot;300; url=target.jsp&quot;＞ <br>　　它的含义：在5分钟之后正在浏览的页面将会自动变为target.html这一页。代码中300为刷新的延迟时间，以秒为单位。targer.html为你想转向的目标页,若为本页则为自动刷新本页。 <br>　　由上可知，可以通过setHeader来实现某页面停留若干秒后,自动重定向到另一页面。 <br>　　关键代码： <br>String content=stayTime+&quot;;URL=&quot;+URL; <br>response.setHeader(&quot;REFRESH&quot;,content); <!--v:3.2--> ]]></description>
<category><![CDATA[JSP]]></category>
<author><![CDATA[94164590@qq.com(木枫)]]></author>
<comments>http://94164590.qzone.qq.com/blog/1250150206#comment</comments>
<qz:effect>134218240</qz:effect>
<pubDate>Thu, 13 Aug 2009 07:56:46 GMT</pubDate>
<guid>http://94164590.qzone.qq.com/blog/1250150206</guid>
</item>

<item>
<title><![CDATA[jsp基础速成精华讲解]]></title>
<link>http://94164590.qzone.qq.com/blog/1250149999</link>
<description><![CDATA[<span style="font-size:16px;line-height:1.8em;">Servlet三个要素:  <br>1.必须继承自HttpServlet  <br>2.必须实现doGet()或者doPost()  <br>3.必须在web.xml中配置Servlet  <br>&lt;servlet&gt;  <br>&lt;servlet-name&gt; &lt;/servlet-name&gt;  <br>&lt;servlet-class&gt; &lt;/servlet-class&gt;  <br>&lt;/servlet&gt;  <br>&lt;servlet-mapping&gt;  <br>&lt;servlet-name&gt; &lt;/servlet-name&gt;  <br>&lt;url-pattern&gt; &lt;/url-pattern&gt;  <br>&lt;/servelt-mapping&gt;  <br>HttpServeltRrequest:请求对象  <br>getParameter():获得表单元素的值  <br>getAttribute():获得request范围中的属性值  <br>setAttribute():设置reqeust范围中的属性值  <br>setCharacterEncoding():设置字符编码  <br>HttpSerletResponse:相应对象  <br>sendRedirect():外部跳转  <br>getWriter():获得输出流对象  <br>setContentType(&quot;text/html; charset=utf-8&quot;):设置相应内容格式和编码  <br>四种会话跟踪方式:  <br>1.Session  <br>HttpSession session = request.getSession();  <br>session.setAttribute(&quot;name&quot;, &quot;zhangsan&quot;);  <br>session.setAttribute(&quot;pwd&quot;, &quot;aaa&quot;);  <br>String name = (String) session.getAttribute(&quot;name&quot;);  <br>2.cookie:  <br>//创建Cookie  <br>Cookie cookie = new Cookie(&quot;name&quot;, &quot;zhangsan&quot;);  <br>//设置Cookie的超时时间  <br>cookie.setMaxAge(24 * 60 * 60 *60);  <br>//把Cookie发送到客户端  <br>response.addCookie(cookie);  <br>//得到客户端发送的Cookie  <br>Cookie [] cookies = request.getCookies();  <br>for(int i=0; i &lt;cookies.length; i++) {  <br>Cookie temp = cookies;  <br>String key = temp.getName();  <br>String value = temp.getValue();  <br>}  <br>3.隐藏表单域  <br>&lt;input type=&quot;hidden&quot; name=&quot;name&quot; value=&quot;zhangsan&quot; /&gt;  <br>request.getParameter(&quot;name&quot;);  <br>4.Url重写  <br>问号传参  <br>LoginServlet?username=zhangsan&amp;pwd=123  <br>String name = request.getParameter(&quot;username&quot;);  <br>String pwd =request.getPareameter(&quot;pwd&quot;);  <br>内部跳转:  <br>LoginServlet  <br>request.getRequestDispatcher(&quot;index.jsp&quot;).forward(request, resposne);  <br>外部跳转:  <br>response.sendRedirect(&quot;index.jsp&quot;);  <br>内部跳转是一次请求和一次响应  <br>外部跳转是两次请求和两次响应  <br>ServletContext:Servlet上下文对象  <br>它是一个公共区域,可以被所有的客户端共享  <br>setAttribute():向公共区域里放入数据  <br>getAttribute():从公共区域里取数据  <br>二:  <br>三:三个标准范围:request, session, ServletContext  <br>共同点:都有setAttribute(), getAttribute()  <br>区别:范围不同,request &lt; session &lt; servletContext  <br>四:四种会话跟踪方式  <br>五:服务器上的五大对象  <br>request, response, servlet, session, servletContext  <br> <br>Jsp:Java Server Page  <br>页面构成:7种元素  <br>1.静态内容:html  <br>2.指令:page, include, taglib:  <br>&lt;%@ 指令名 属性1=&quot;属性值1&quot; 属性2=&quot;属性值2&quot; %&gt;  <br>3.表达式: &lt;%=表达式 %&gt;  <br>4.Scriptlet &lt;% Java代码 %&gt;  <br>5.声明: &lt;%! %&gt;:变量和方法  <br>6.动作: &lt;jsp:动作名 属性=&quot;属性值&quot;&gt; &lt;/jsp:动作名&gt;  <br>7.注释:  <br>客户端看不到的: &lt;%-- --%&gt;  <br>客户端可以看到的: &lt;!-- --&gt; </span><wbr /><span style="font-size:16px;line-height:1.8em;">Jsp的执行过程:  <br>1.转译:Jsp---&gt;Servlet  <br>2.编译:Servlet----&gt;.class  <br>3.执行:.class  <br>第一次访问jsp的时候响应速度较慢,后面请求时响应速度快  <br>脚本:  <br>表达式: &lt;%= %&gt;  <br>Scriptlet: &lt;% %&gt;  <br>声明: &lt;%! %&gt;  <br>指令:  <br>page:language, import, errorPage, isErrorpage  <br>include:file  <br>taglib:uri:指定标签库描述符的路径 prefix:指定标签的前缀  <br>隐式对象:  <br>分类:  <br>1.输入和输出对象:request(HttpServletRequest),  <br>                response(HttpServletResponse),  <br>                out(JspWriter), servlet中的out是PrintWriter  <br>2.作用域通信对象:pageContext, request,  <br>                session(HttpSession),  <br>                application(ServletContext)  <br>3.Servlet对象:page(this), config  <br>4.错误对象:exception  <br>     <br>JavaBean:  <br>一个标准的JavaBean有三个条件  <br>1.共有的类  <br>2.具有不带参数的公共的构造方法  <br>3.具有set()和get()方法  <br>4.私有属性  <br>Jsp中的标准动作:  <br>1.useBean:创建JavaBean的一个实例  <br>&lt;jsp:useBean id=&quot;stu&quot; class=&quot;com.westaccp.test.Student&quot; scope=&quot;page/session/application/request&quot; /&gt;  <br>2.setProperty:给JavaBean的属性赋值  <br>&lt;jsp:setProperty name=&quot;stu&quot; property=&quot;stuName&quot; value=&quot;zhangsan&quot; /&gt;  <br>&lt;jsp:setProperty name=&quot;stu&quot; property=&quot;stuName&quot; param=&quot;txtName&quot; /&gt;  <br>value和param不能同时使用  <br>偷懒的方法: &lt;jsp:setProperty name=&quot;stu&quot; property=&quot;*&quot; /&gt;  <br>这个时候需要注意的是,表单元素的名字必须和JavaBean的属性值  <br>一模一样  <br>3.getProperty:获得JvaBean的属性值  <br>&lt;jsp:getProperty name=&quot;stu&quot; property=&quot;stuName&quot; /&gt;  <br>4.forward:内部跳转,相当于request.getRequestDispatcher().forward(request, response);  <br>&lt;jsp:forward page=&quot;index.jsp&quot; /&gt;  <br>5.include:包含  <br>&lt;jsp:include page=&quot;header.jsp&quot; flush=&quot;true&quot; /&gt;  <br>表达式语言:  <br>EL: Expression Language  <br>语法格式: ${表达式 }  <br>表示式 = 运算符 + 操作数  <br>运算符:跟Java比较,多了一个empty, 少了一个赋值运算符  <br>${empty &quot;&quot;} : true  <br>${empty null} :true  <br>操作数:  <br>--&gt;常量:布尔型(true/false), 整型, 浮点型, 字符串(可以用'', 还可以用&quot;&quot;), Null  <br>--&gt;变量:  <br>    1.指的是放在四个标准范围里的属性(page, request, session, application)  <br>    2.在编准范围内的搜索顺序:page--&gt;request---&gt;session---&gt;application  <br>    3.怎么取得变量值:点运算符., 还以用[]  <br>    &lt;%  <br>      request.setAttribute(&quot;name&quot;, &quot;lisi&quot;);  <br>    %&gt;  <br>    ${requestScope.name}  <br>    或者  <br>    ${requestScope[&quot;name&quot;]}  <br>--&gt;隐式对象  <br>    1.pageContext:通过它可以访问request, session, servletContext  <br>    2.跟范围由关的:pageScope, requestScope, sessionScope, applicationScope  <br>    3.跟输入有关的:param, paramValues  <br>    4.其他的:header, cookie, headervalues,  <br>EL表达式适用的场合:  <br>1.可以在静态文本中使用  <br>2.与自定义标签结合使用  <br>3.和JavaBean结合使用  <br>&lt;jsp:userBean id=&quot;stu&quot; class=&quot;com.westaccp.test.Student&quot; scope=&quot;session&quot; /&gt;  <br>&lt;jsp:setProperty name=&quot;stu&quot; property=&quot;stuName&quot; value=&quot;hello&quot; /&gt;  <br>${stu.stuName}  <br>自定义标签:  <br>1.标签处理程序实现  <br>---&gt;实现:继承自BodyTagSupport或者TagSupport  <br>          一般会重写doStartTag(), doEndTag(), doAfterBody()  <br>---&gt;描述:在标签库描述符文件中描述(.tld)  <br>    &lt;taglib&gt;  <br>      &lt;tlib-version&gt;1.0 &lt;/tlib-version&gt;  <br>      &lt;jsp-version&gt;2.0 &lt;/jsp-version&gt;  <br>      &lt;short-name&gt;simpletag &lt;/short-name&gt;  <br>     <br>      &lt;tag&gt;  <br>        &lt;name&gt;showbody &lt;/name&gt;  <br>        &lt;tag-class&gt;com.westaccp.test.ShowBodyTag &lt;/tag-class&gt;  <br>        &lt;body-content&gt;empty/jsp &lt;/body-content&gt;  <br>        &lt;attribute&gt;  <br>        &lt;name&gt;color &lt;/name&gt;  <br>        &lt;/attribute&gt;  <br>      &lt;/tag&gt;  <br>    &lt;/taglib&gt;  <br>---&gt;使用: &lt;%@ taglib uri=&quot;WEB-INF/mytag.tld&quot; prefix=&quot;my&quot; %&gt;  <br>          &lt;my:showbody /&gt;  <br>2.标签文件  <br>---&gt;实现和描述  <br>    在.tag文件中实现  <br>    设置主体内容: &lt;%@ body-content=&quot;empty/scriptless&quot; %&gt;  <br>    设置属性: &lt;%@ attribute name=&quot;name&quot; required=&quot;true&quot; rtexprvalue=&quot;true&quot; %&gt;  <br>    有主体内容: &lt;jsp:doBody scope=&quot;session&quot; var=&quot;theBody&quot; /&gt;  <br>    &lt;%  <br>        String body = (String) session.getAttribute(&quot;theBody&quot;);  <br>    %&gt;  <br>---&gt;使用  <br>    WEB-INF/tags/sayhello.tag  <br>    &lt;%@ taglib tagdir=&quot;/WEB-INF/tags/&quot; prefix=&quot;you&quot; %&gt;  <br>    &lt;you:sayhello /&gt;  <br>     <br>标准标签库:  <br>1.核心标签库  <br>--&gt;通用:  <br>    set: &lt;c:set var=&quot;&quot; value=&quot;&quot; scope=&quot;&quot; /&gt;  <br>    out: &lt;cut value=&quot;&quot; /&gt;  <br>    remove: &lt;c:remove var=&quot;&quot; scope=&quot;&quot; /&gt;  <br>--&gt;条件:  <br>    if: &lt;c:if test=&quot;&quot;&gt;..... &lt;/c:if&gt;  <br>    choose: &lt;c:choose&gt;  <br>            &lt;c:when test=&quot;&quot;&gt;... &lt;/c:when&gt;  <br>            &lt;c:when test=&quot;&quot;&gt;... &lt;/c:when&gt;  <br>            &lt;c:when test=&quot;&quot;&gt;... &lt;/c:when&gt;  <br>                .....  <br>                &lt;ctherwise&gt;... &lt;/otherwise&gt;           <br>            &lt;/c:choose&gt;  <br>--&gt;迭代:  <br>    forEach: &lt;forEach var=&quot;&quot; items=&quot;&quot; varStatus=&quot;&quot; begin=&quot;&quot; end=&quot;&quot;&gt;  <br>    foTokens: &lt;foTodens var=&quot;&quot; items=&quot;&quot; delim=&quot;,;|&quot;&gt; &lt;/foTodens&gt;  <br>    Java,C#;SQL|C  <br>2.I18N与格式化标签库  <br>--&gt;setLocale:设置本地区域  <br>--&gt;bundle:设置资源包  <br>--&gt;setBundle:设置资源包  <br>--&gt;message:输出消息  <br>3.SQL标签库  <br>--&gt;setDataSource:设置数据源,用于获得与数据库的连接  <br>--&gt;query:执行查询  <br>--&gt;update:执行增,删,改  <br>--&gt;transaction:事务  <br>--&gt;param:参数  <br>4.XML标签库  <br>过滤器:  <br>生命周期:  <br>1.实例华:  <br>2.初始化:init()  <br>3.过滤:doFilter()  <br>4.销毁:destroy()  <br>5.不可用  <br>配置:  <br>&lt;filter&gt;  <br>&lt;filter-name&gt; &lt;/filter-name&gt;  <br>&lt;filter-class&gt; &lt;/filter-class&gt;  <br>&lt;/filter&gt;  <br>&lt;filter-mapping&gt;  <br>&lt;filter-name&gt; &lt;/filter-name&gt;  <br>&lt;url-pattern&gt; &lt;/url-pattern&gt;  <br>&lt;/filter-mapping&gt;  <br>几个重要的接口:  <br>1.Filter:init(), doFilter(), destroy()  <br>2.FilterChain: doFilter(request, response)  <br>3.FilterConfig:getFilterName(), getInitParameter(),  <br>过滤器链:---&gt;1---&gt;2---&gt;3---&gt;Servlet 请求  <br>        &lt;----1 &lt;---2 &lt;---3 &lt;---        响应  <br>         <br>MvC设计模式  <br>1.ModelI:jsp+JavaBean  <br>2.ModelII:jsp+Servlet+JavaBean  <br>          jsp---view  <br>          servlet---control  <br>          javabean---model  <br>MVC:  <br>M--Model:模型:访问后台数据库  <br>V--view:视图:展示  <br>C--control:控制器:控制程序流程  <br>ModelII和MVC的关系:  <br>MVC是一种设计模式,ModelII它是MVC的一种具体的实现</span><wbr /> <!--v:3.2--> ]]></description>
<category><![CDATA[JSP]]></category>
<author><![CDATA[94164590@qq.com(木枫)]]></author>
<comments>http://94164590.qzone.qq.com/blog/1250149999#comment</comments>
<qz:effect>134218240</qz:effect>
<pubDate>Thu, 13 Aug 2009 07:53:19 GMT</pubDate>
<guid>http://94164590.qzone.qq.com/blog/1250149999</guid>
</item>

<item>
<title><![CDATA[提升JSP应用程序的七大绝招]]></title>
<link>http://94164590.qzone.qq.com/blog/1250149937</link>
<description><![CDATA[你时常被客户抱怨JSP页面响应速度很慢吗？你想过当客户访问次数剧增时，你的WEB应用能承受日益增加的访问量吗？ <br> <br>本文讲述了调整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>public class ControllerServlet extends HttpServlet {  <br>　private javax.sql.DataSource testDS = null;  <br>　public void init(ServletConfig config) throws ServletException 　{ 　 <br>　super.init(config); 　 <br>　Context ctx = null; 　 <br>　try 　　{ 　　 <br>　ctx = new InitialContext(); 　 <br>　　testDS = (javax.sql.DataSource)ctx.lookup(&quot;jdbc/testDS&quot;); 　 <br>　} 　　catch(NamingException ne) 　　{ 　　 <br>　ne.printStackTrace(); 　 <br>　} 　　catch(Exception e) 　　{ 　 <br>　　e.printStackTrace(); 　 <br>　} 　 <br>}  <br>　public javax.sql.DataSource getTestDS() 　{ 　 <br>　return testDS; 　 <br>}  <br>　... 　...  <br>} <br> <br>　　方法 2:禁止servlet和JSP 自动重载(auto-reloading) <br> <br>　　Servlet/JSP提供了一个实用的技术，即自动重载技术，它为开发人员提供了一个好的开发环境，当你改变servlet和JSP页面后而不必重启应用服务器。然而，这种技术在产品运行阶段对系统的资源是一个极大的损耗，因为它会给JSP引擎的类装载器(classloader)带来极大的负担。因此关闭自动重载功能对系统性能的提升是一个极大的帮助。 <br> <br>　　方法 3: 不要滥用HttpSession <br> <br>　　在很多应用中，我们的程序需要保持客户端的状态，以便页面之间可以相互联系。但不幸的是由于HTTP具有天生无状态性，从而无法保存客户端的状态。因此一般的应用服务器都提供了session来保存客户的状态。在JSP应用服务器中，是通过HttpSession对像来实现session的功能的，但在方便的同时，它也给系统带来了不小的负担。因为每当你获得或更新session时，系统者要对它进行费时的序列化操作。你可以通过对HttpSession的以下几种处理方式来提升系统的性能： <br> <br>如果没有必要，就应该关闭JSP页面中对HttpSession的缺省设置： 如果你没有明确指定的话，每个JSP页面都会缺省地创建一个HttpSession。如果你的JSP中不需要使用session的话，那可以通过如下的JSP页面指示符来禁止它： ＜%@ page session=&quot;false&quot;%＞ <br> <br>不要在HttpSession中存放大的数据对像：如果你在HttpSession中存放大的数据对像的话，每当对它进行读写时，应用服务器都将对其进行序列化，从而增加了系统的额外负担。你在HttpSession中存放的数据对像越大，那系统的性能就下降得越快。 <br> <br>当你不需要HttpSession时，尽快地释放它：当你不再需要session时，你可以通过调用HttpSession.invalidate()方法来释放它。 <br> <br>尽量将session的超时时间设得短一点：在JSP应用服务器中，有一个缺省的session的超时时间。当客户在这个时间之后没有进行任何操作的话，系统会将相关的session自动从内存中释放。超时时间设得越大，系统的性能就会越低，因此最好的方法就是尽量使得它的值保持在一个较低的水平。 <br> <br>　方法 4: 将页面输出进行压缩 <br> <br>　　压缩是解决数据冗余的一个好的方法，特别是在网络带宽不够发达的今天。有的浏览器支持gzip(GNU zip)进行来对HTML文件进行压缩，这种方法可以戏剧性地减少HTML文件的下载时间。因此，如果你将servlet或JSP页面生成的HTML页面进行压缩的话，那用户就会觉得页面浏览速度会非常快。但不幸的是，不是所有的浏览器都支持gzip压缩，但你可以通过在你的程序中检查客户的浏览器是否支持它。下面就是关于这种方法实现的一个代码片段： <br> <br>public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {  <br>　OutputStream out = null; <br>　String encoding = request.getHeader(&quot;Accept-Encoding&quot;);  <br>　if (encoding != null &amp;&amp; encoding.indexOf(&quot;gzip&quot;) != -1) 　{ 　 <br>　request.setHeader(&quot;Content-Encoding&quot; , &quot;gzip&quot;);  <br>　　out = new GZIPOutputStream(request.getOutputStream()); 　 <br>} 　else if (encoding != null &amp;&amp; encoding.indexOf(&quot;compress&quot;) != -1) 　{ 　 <br>　request.setHeader(&quot;Content-Encoding&quot; , &quot;compress&quot;); 　 <br>　out = new ZIPOutputStream(request.getOutputStream());  <br>　} 　else 　{  <br>　　out = request.getOutputStream();  <br>　}  <br>　... 　...  <br>} <br> <br>　　方法 5: 使用线程池 <br> <br>　　应用服务器缺省地为每个不同的客户端请求创建一个线程进行处理，并为它们分派service()方法，当service()方法调用完成后，与之相应的线程也随之撤消。由于创建和撤消线程会耗费一定的系统资源，这种缺省模式降低了系统的性能。但所幸的是我们可以通过创建一个线程池来改变这种状况。另外，我们还要为这个线程池设置一个最小线程数和一个最大线程数。在应用服务器启动时，它会创建数量等于最小线程数的一个线程池，当客户有请求时，相应地从池从取出一个线程来进行处理，当处理完成后，再将线程重新放入到池中。如果池中的线程不够地话，系统会自动地增加池中线程的数量，但总量不能超过最大线程数。通过使用线程池，当客户端请求急剧增加时，系统的负载就会呈现的平滑的上升曲线，从而提高的系统的可伸缩性。 <br> <br>　　方法 6: 选择正确的页面包含机制 <br>　　在JSP中有两种方法可以用来包含另一个页面1、使用include指示符(＜%@ includee file=”test.jsp” %＞)。2、使用jsp指示符(＜jsp:includee page=”test.jsp” flush=”true”/＞)。在实际中我发现，如果使用第一种方法的话，可以使得系统性能更高。 <br> <br>　　方法 7:正确地确定javabean的生命周期 <br> <br>　　JSP的一个强大的地方就是对javabean的支持。通过在JSP页面中使用＜jsp:useBean＞标签，可以将javabean直接插入到一个JSP页面中。它的使用方法如下： ＜jsp:useBean id=&quot;name&quot; scope=&quot;page|request|session|application&quot; class= &quot;package.className&quot; type=&quot;typeName&quot;＞＜/jsp:useBean＞ <br> <br>　　其中scope属性指出了这个bean的生命周期。缺省的生命周期为page。如果你没有正确地选择bean的生命周期的话，它将影响系统的性能。 <br> <br>　　举例来说，如果你只想在一次请求中使用某个bean，但你却将这个bean的生命周期设置成了session，那当这次请求结束后，这个bean将仍然保留在内存中，除非session超时或用户关闭浏览器。这样会耗费一定的内存，并无谓的增加了JVM垃圾收集器的工作量。因此为bean设置正确的生命周期，并在bean的使命结束后尽快地清理它们，会使用系统性能有一个提高。 <br> <br>　　其它一些有用的方法  <br>　　? 在字符串连接操作中尽量不使用“＋”操作符：在java编程中，我们常常使用“＋”操作符来将几个字符串连接起来，但你或许从来没有想到过它居然会对系统性能造成影响吧？由于字符串是常量，因此JVM会产生一些临时的对像。你使用的“＋”越多，生成的临时对像就越多，这样也会给系统性能带来一些影响。解决的方法是用StringBuffer对像来代替“＋”操作符。 <br> <br>　　? 避免使用System.out.println()方法：由于System.out.println()是一种同步调用，即在调用它时，磁盘I/O操作必须等待它的完成，因此我们要尽量避免对它的调用。但我们在调试程序时它又是一个必不可少的方便工具，为了解决这个矛盾，我建议你最好使用Log4j工具(http://Jakarta.apache.org ; )，它既可以方便调试，而不会产生System.out.println()这样的方法。 <br> <br>　　? ServletOutputStream 与 PrintWriter的权衡:使用PrintWriter可能会带来一些小的开销，因为它将所有的原始输出都转换为字符流来输出，因此如果使用它来作为页面输出的话，系统要负担一个转换过程。而使用ServletOutputStream作为页面输出的话就不存在一个问题，但它是以二进制进行输出的。因此在实际应用中要权衡两者的利弊。 <br> <br>　　总结。 <br> <br>本文的目的是通过对servlet和JSP的一些调优技术来极大地提高你的应用程序的性能，并因此提升整个J2EE应用的性能。通过这些调优技术，你可以发现其实并不是某种技术平台（比如J2EE和.NET之争）决定了你的应用程序的性能，重要是你要对这种平台有一个较为深入的了解，这样你才能从根本上对自己的应用程序做一个优化！ <!--v:3.2--> ]]></description>
<category><![CDATA[JSP]]></category>
<author><![CDATA[94164590@qq.com(木枫)]]></author>
<comments>http://94164590.qzone.qq.com/blog/1250149937#comment</comments>
<qz:effect>134218240</qz:effect>
<pubDate>Thu, 13 Aug 2009 07:52:17 GMT</pubDate>
<guid>http://94164590.qzone.qq.com/blog/1250149937</guid>
</item>

<item>
<title><![CDATA[JSP分页技术]]></title>
<link>http://94164590.qzone.qq.com/blog/1250149878</link>
<description><![CDATA[前言 <br>     在使用数据库的过程中，不可避免的需要使用到分页的功能，可是JDBC的规范对此却没有很好的解决。对于这个需求很多朋友都有自己的解决方案，比如使用Vector等集合类先保存取出的数据再分页。但这种方法的可用性很差，与JDBC本身的接口完全不同，对不同类型的字段的支持也不好。这里提供了一种与JDBC兼容性非常好的方案。   <br> JDBC和分页 <br>　　Sun的JDBC规范的制定，有时很让人哭笑不得，在JDBC1.0中，对于一个结果集（ResultSet）你甚至只能执行next()操作，而无法让其向后滚动，这就直接导致在只执行一次SQL查询的情况下无法获得结果集的大小。所以，如果你使用的是JDBC1.0的驱动，那么是几乎无法实现分页的。 <br>　　好在Sun的JDBC2规范中很好的弥补了这一个不足，增加了结果集的前后滚动操作，虽然仍然不能直接支持分页，但我们已经可以在这个基础上写出自己的可支持分页的ResultSet了。 和具体数据库相关的实现方法 <br>　　有一些数据库，如Mysql, Oracle等有自己的分页方法，比如Mysql可以使用limit子句，Oracle可以使用ROWNUM来限制结果集的大小和起始位置。这里以Mysql为例，其典型代码如下：  <br>    // 计算总的记录条数 <br>    String SQL = &quot;SELECT Count(*) AS total &quot; + this.QueryPart;  <br>    rs = db.executeQuery(SQL);     <br>    if (rs.next())  <br>    Total = rs.getInt(1);      <br>    // 设置当前页数和总页数 <br>    TPages = (int)Math.ceil((double)this.Total/this.MaxLine);  <br>    CPages = (int)Math.floor((double)Offset/this.MaxLine+1);  <br>    // 根据条件判断，取出所需记录 <br>    if (Total &gt; 0) {  <br>      SQL = Query + &quot; LIMIT &quot; + Offset + &quot; , &quot; + MaxLine;  <br>      rs = db.executeQuery(SQL);        <br>    }     <br>    return rs;  <br>  }   <br>　　毫无疑问，这段代码在数据库是Mysql时将会是漂亮的，但是作为一个通用的类（事实上我后面要提供的就是一个通用类库中的一部分），需要适应不同的数据库，而基于这个类（库）的应用，也可能使用不同的数据库，所以，我们将不使用这种方法。 <br> 另一种繁琐的实现方法 <br>　　我看过一些人的做法（事实上包括我在内，一开始也是使用这种方法的），即不使用任何封装，在需要分页的地方，直接操作ResultSet滚到相应的位置，再读取相应数量的记录。其典型代码如下：  <br>&lt;% <br>sqlStmt = sqlCon.createStatement(java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, <br>java.sql.ResultSet.CONCUR_READ_ONLY); <br>strSQL = &quot;select name,age from test&quot;; <br>//执行SQL语句并获取结果集 <br>sqlRst = sqlStmt.executeQuery(strSQL); <br>//获取记录总数 <br>sqlRst.last(); <br>intRowCount = sqlRst.getRow(); <br>//记算总页数 <br>intPageCount = (intRowCount+intPageSize-1) / intPageSize; <br>//调整待显示的页码 <br>if(intPage&gt;intPageCount) intPage = intPageCount; <br>%&gt; <br>&lt;table border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt; <br>&lt;tr&gt; <br>   &lt;th&gt;姓名&lt;/th&gt; <br>   &lt;th&gt;年龄&lt;/th&gt; <br>&lt;/tr&gt; <br>&lt;% <br>if(intPageCount&gt;0){ <br>   //将记录指针定位到待显示页的第一条记录上 <br>   sqlRst.absolute((intPage-1) * intPageSize + 1); <br>   //显示数据 <br>   i = 0; <br>   while(i&lt;intPageSize &amp;&amp; !sqlRst.isAfterLast()){ <br>      %&gt; <br>&lt;tr&gt; <br>   &lt;td&gt;&lt;%=sqlRst.getString(1)%&gt;&lt;/td&gt; <br>   &lt;td&gt;&lt;%=sqlRst.getString(2)%&gt;&lt;/td&gt; <br>&lt;/tr&gt; <br>      &lt;% <br>      sqlRst.next(); <br>      i++; <br>   } <br>} <br>%&gt; <br>&lt;/table&gt;   <br>　　很显然，这种方法没有考虑到代码重用的问题，不仅代码数量巨大，而且在代码需要修改的情况下，将会无所适从。 <br> 使用Vector进行分页 <br>　　还见过另一些实现分页的类，是先将所有记录都select出来，然后将ResultSet中的数据都get出来，存入Vector等集合类中，再根据所需分页的大小，页数，定位到相应的位置，读取数据。或者先使用前面提到的两种分页方法，取得所需的页面之后，再存入Vector中。 <br>　　扔开代码的效率不说，单是从程序结构和使用的方便性上讲，就是很糟糕的。比如，这种做法支持的字段类型有限，int, double, String类型还比较好处理，如果碰到Blob, Text等类型，实现起来就很麻烦了。这是一种更不可取的方案。 <br> 一个新的Pageable接口及其实现 <br>　　很显然，看过上面三种实现方法后，我们对新的分页机制有了一个目标，即：不与具体数据库相关；尽可能做到代码重用；尽可能与原JDBC接口的使用方法保持一致；尽可能高的效率。 <br>　　首先，我们需要提供一个与java.sql.ResultSet向下兼容的接口，把它命名为Pageable，接口定义如下： <br>public interface Pageable extends java.sql.ResultSet{ <br>/**返回总页数 <br>*/ <br>int getPageCount(); <br>/**返回当前页的记录条数 <br>*/ <br>int getPageRowsCount(); <br>/**返回分页大小 <br>*/ <br>int getPageSize(); <br>/**转到指定页 <br>*/ <br>void gotoPage(int page) ; <br>/**设置分页大小 <br>*/ <br>void setPageSize(int pageSize); <br>/**返回总记录行数 <br>*/ <br>int getRowsCount(); <br>/** <br> * 转到当前页的第一条记录 <br> * @exception java.sql.SQLException 异常说明。 <br> */ <br>void pageFirst() throws java.sql.SQLException; <br>/** <br> * 转到当前页的最后一条记录 <br> * @exception java.sql.SQLException 异常说明。 <br> */ <br>void pageLast() throws java.sql.SQLException; <br>/**返回当前页号 <br>*/ <br>int getCurPage(); <br>}   <br>　　这是一个对java.sql.ResultSet进行了扩展的接口，主要是增加了对分页的支持，如设置分页大小，跳转到某一页，返回总页数等等。 <br>　　接着，我们需要实现这个接口，由于这个接口继承自ResultSet，并且它的大部分功能也都和ResultSet原有功能相同，所以这里使用了一个简单的Decorator模式。 <br>　　PageableResultSet2的类声明和成员声明如下： <br>public class PageableResultSet2 implements Pageable { <br>    protected java.sql.ResultSet rs=null; <br>    protected int rowsCount; <br>    protected int pageSize; <br>    protected int curPage; <br>    protected String command = &quot;&quot;; <br>}   <br>　　可以看到，在PageableResultSet2中，包含了一个ResultSet的实例（这个实例只是实现了ResultSet接口，事实上它是由各个数据库厂商分别实现的），并且把所有由ResultSet继承来的方法都直接转发给该实例来处理。 <br>　　PageableResultSet2中继承自ResultSet的主要方法： <br>//…… <br>public boolean next() throws SQLException { <br>    return rs.next(); <br>} <br>//…… <br>public String getString(String columnName) throws SQLException { <br>    try { <br>        return rs.getString(columnName); <br>    } <br>    catch (SQLException e) {//这里是为了增加一些出错信息的内容便于调试 <br>        throw new SQLException (e.toString()+&quot; columnName=&quot; <br>            +columnName+&quot; SQL=&quot;+this.getCommand()); <br>    } <br>} <br>//……   <br>　　只有在Pageable接口中新增的方法才需要自己的写方法处理。 <br>/**方法注释可参考Pageable.java <br>*/ <br>public int getCurPage() { <br>    return curPage; <br>} <br>public int getPageCount() { <br>    if(rowsCount==0) return 0; <br>    if(pageSize==0) return 1; <br>    //calculate PageCount <br>    double tmpD=(double)rowsCount/pageSize; <br>    int tmpI=(int)tmpD; <br>    if(tmpD&gt;tmpI) tmpI++; <br>    return tmpI; <br>} <br>public int getPageRowsCount() { <br>    if(pageSize==0) return rowsCount; <br>    if(getRowsCount()==0) return 0; <br>    if(curPage!=getPageCount()) return pageSize; <br>    return rowsCount-(getPageCount()-1)*pageSize; <br>} <br>public int getPageSize() { <br>    return pageSize; <br>} <br>public int getRowsCount() { <br>    return rowsCount; <br>} <br>public void gotoPage(int page) { <br>    if (rs == null) <br>        return; <br>    if (page &lt; 1) <br>        page = 1; <br>    if (page &gt; getPageCount()) <br>        page = getPageCount(); <br>    int row = (page - 1) * pageSize + 1; <br>    try { <br>        rs.absolute(row); <br>        curPage = page; <br>    } <br>    catch (java.sql.SQLException e) { <br>    } <br>} <br>public void pageFirst() throws java.sql.SQLException { <br>    int row=(curPage-1)*pageSize+1; <br>    rs.absolute(row); <br>} <br>public void pageLast() throws java.sql.SQLException { <br>    int row=(curPage-1)*pageSize+getPageRowsCount(); <br>    rs.absolute(row); <br>} <br>public void setPageSize(int pageSize) { <br>    if(pageSize&gt;=0){ <br>        this.pageSize=pageSize; <br>        curPage=1; <br>    } <br>}   <br>　　PageableResultSet2的构造方法： <br>public PageableResultSet2(java.sql.ResultSet rs) throws java.sql.SQLException { <br>    if(rs==null) throw new SQLException(&quot;given ResultSet is NULL&quot;,&quot;user&quot;); <br>     <br>    rs.last(); <br>    rowsCount=rs.getRow(); <br>    rs.beforeFirst(); <br>     <br>    this.rs=rs; <br>}   <br>　　这里只是简单的取得一个总记录数，并将记录游标移回初始位置（before first），同时将参数中的ResultSet赋给成员变量。 <br> Pageable的使用方法 <br>　　因为Pageable接口继承自ResultSet，所以在使用方法上与ResultSet一致，尤其是在不需要分页功能的时候，可以直接当成ResultSet使用。而在需要分页时，只需要简单的setPageSize, gotoPage，即可。 <br>PreparedStatement pstmt=null; <br>Pageable rs=null; <br>……//构造SQL，并准备一个pstmt. <br>rs=new PageableResultSet2(pstmt.executeQuery());//构造一个Pageable <br>rs.setPageSize(20);//每页20个记录 <br>rs.gotoPage(2);//跳转到第2页 <br>for(int i=0; i&lt;rs.getPageRowsCount(); i++){//循环处理 <br>int id=rs.getInt(“ID”); <br>……//继续处理rs.next(); <br>}   <br> 总结 <br>　　一个好的基础类应该是便于使用，并且具备足够的可移植性，同时要保证其功能的完善。在上面的实现中，我们从java.sql.ResultSet接口继承出Pageable，并实现了它。这就保证了在使用中与JDBC原有操作的一致性，同时对原有功能没有缩减。 <br>　　同时它也是易于使用的，因为封装了一切必要的操作，所以在你的代码中唯一显得&quot;难看&quot;和&quot;不舒服&quot;的地方就是需要自己去构造一个PageableResultSet2。不过只要你愿意，这也是可以解决的。 <br>　　当然它也有具有充分的可移植性，当你将数据库由Oracle变为Mysql或者SQLServer的时候，你仍然可以使用这些分页的代码。它在使用中（或者说在移植的过程中）唯一的限制就是你必须要使用一个支持JDBC2的驱动（现在明白为什么我把类命名为PageableResultSet2了吧。:P），不过，好在JDBC2已经成为标准了，绝大多数的数据库（如Oracle, Mysql, SQLServer）都有自己的或者第三方提供的JDBC2的驱动。 <!--v:3.2--> ]]></description>
<category><![CDATA[JSP]]></category>
<author><![CDATA[94164590@qq.com(木枫)]]></author>
<comments>http://94164590.qzone.qq.com/blog/1250149878#comment</comments>
<qz:effect>134218240</qz:effect>
<pubDate>Thu, 13 Aug 2009 07:51:18 GMT</pubDate>
<guid>http://94164590.qzone.qq.com/blog/1250149878</guid>
</item>

<item>
<title><![CDATA[EXTJS与JSP注册窗口]]></title>
<link>http://94164590.qzone.qq.com/blog/1250149133</link>
<description><![CDATA[<span style="color:#ff9900;line-height:1.8em;">&lt;!-- 首先前台部分使用extjs写一个简单的注册窗口 文件名为 login.html --&gt;</span><wbr /> <br> <br>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;<a href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" target="_blank">http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd</a><wbr />&quot;&gt; <br>&lt;html xmlns=&quot;<a href="http://www.w3.org/1999/xhtml" target="_blank">http://www.w3.org/1999/xhtml</a><wbr />&quot;&gt; <br>&lt;head&gt; <br>&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt; <br>&lt;title&gt;extDemo&lt;/title&gt; <br>&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;ext/resources/css/ext-all.css&quot; /&gt;  <br>&lt;script type=&quot;text/javascript&quot; src=&quot;ext/adapter/ext/ext-base.js&quot;&gt;&lt;/script&gt; <br>&lt;script type=&quot;text/javascript&quot; src=&quot;ext/ext-all.js&quot;&gt;&lt;/script&gt; <br>&lt;/head&gt; <br>&lt;body&gt; <br>&lt;script&gt; <br>Ext.onReady(function(){  <br>          //使用表单提示 <br>          Ext.QuickTips.init(); <br>          Ext.form.Field.prototype.msgTarget = 'side'; <br>                   <br>                  //定义表单 <br>          var simple = new Ext.FormPanel({ <br>                                labelWidth: 75,                          <br>                                baseCls: 'x-plain', <br>                                defaults: {width: 150}, <br>                                defaultType: 'textfield',//默认字段类型 <br>                  <br>                                //定义表单元素 <br>                                items: [{ <br>                                                fieldLabel: '帐户', <br>                                                name: 'name',//元素名称 <br>                                                //anchor:'95%',//也可用此定义自适应宽度 <br>                                                allowBlank:false,//不允许为空 <br>                                                blankText:'帐户不能为空'//错误提示内容 <br>                                        },{ <br>                                            inputType:'password', <br>                                                fieldLabel: '密码', <br>                                                //anchor:'95%', <br>                                                name: 'pws', <br>                                                allowBlank:false, <br>                                                blankText:'密码不能为空' <br>                                        } <br>                                ],                                buttons: [{ <br>                                        text: '提交', <br>                                        type: 'submit', <br>                                        //定义表单提交事件 <br>                                        handler:function(){ <br>                              if(simple.form.isValid()){//验证合法后使用加载进度条 <br>                                                              Ext.MessageBox.show({ <br>                                                                           title: '请稍等', <br>                                                                           msg: '正在加载...', <br>                                                                           progressText: '', <br>                                                                           width:300, <br>                                                                           progress:true, <br>                                                                           closable:false, <br>                                                                           animEl: 'loding' <br>                                                                   }); <br>                                                                   //控制进度速度 <br>                                                                   var f = function(v){ <br>                                                                         return function(){ <br>                                                                                                var i = v/11; <br>                                                                                                Ext.MessageBox.updateProgress(i, ''); <br>                                                                            }; <br>                                                                   };                                                                   for(var i = 1; i &lt; 13; i++){ <br>                                                                                setTimeout(f(i), i*150); <br>                                                                   } <br>                                   <br>                                                                  //提交到服务器操作 <br>                                                                  simple.form.doAction('submit',{ <br>                                                                         [url='check.jsp',//]url:'check.jsp',//[/url]文件路径 <br>                                                                         method:'post',//提交方法post或get <br>                                                                         params:'', <br>                                                                         //提交成功的回调函数 <br>                                                                         success:function(form,action){ <br>                                                                                        if (action.result.msg=='ok') { <br>                                                                                                //document.location='index.html'; <br>                                                                                                Ext.Msg.alert('提示窗口','提交已成功！'); <br>                                                                                        } else { <br>                                                                                                Ext.Msg.alert('登陆错误',action.result.msg); <br>                                                                                        } <br>                                                                         }, <br>                                                                         //提交失败的回调函数 <br>                                                                         failure:function(){ <br>                                                                                        Ext.Msg.alert('错误','服务器出现错误请稍后再试！'); <br>                                                                         } <br>                                                                  }); <br>                                                           }                                                                                <br>                                        } <br>                                },{ <br>                                        text: '取消', <br>                                        handler:function(){simple.form.reset();}//重置表单 <br>                                }] <br>                        });     <br>                               //定义窗体 <br>                                   win = new Ext.Window({ <br>                                                id:'win', <br>                                                title:'注册窗口', <br>                                                layout:'fit',   //之前提到的布局方式fit，自适应布局                                     <br>                                                width:300, <br>                                                height:150, <br>                                                plain:true, <br>                        bodyStyle:'padding:5px;', <br>                                                maximizable:false,//禁止最大化 <br>                                                closeAction:'close', <br>                                                closable:false,//禁止关闭 <br>                                                collapsible:true,//可折叠 <br>                                                plain: true, <br>                                                buttonAlign:'center', <br>                                                items:simple//将表单作为窗体元素嵌套布局 <br>                                        }); <br>                                        win.show();//显示窗体 <br>                                                                                 <br>                 }); <br>&lt;/script&gt; <br>&lt;/body&gt; <br>&lt;/html&gt; <br>  <br>  <br><span style="color:#ff9900;line-height:1.8em;">&lt;!-- 后台部分 这里数据库使用的是Access数据库    本文件名为 check.jsp--&gt;</span><wbr /> <br> <br>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=gb2312&quot; <br>    pageEncoding=&quot;gbk&quot;%&gt; <br>&lt;%@ page import = &quot;java.sql.*,java.util.*&quot; %&gt; <br>&lt;% <br>      request.setCharacterEncoding(&quot;gb2312&quot;); <br>      String name=request.getParameter(&quot;name&quot;); <br>      String pws=request.getParameter(&quot;pws&quot;); <br>      if(name.equals(pws)){ <br>         out.print(&quot;{success:true,msg:\'ok\'}&quot;); <br>      }else{ <br>         out.print(&quot;{success:true,msg:\'帐户或密码错误\'}&quot;); <br>      } <br>       <br>      try{ <br>      String message=pws; <br>      String sourceURL=&quot;jdbc:odbc:driver={Microsoft Access Driver (*.mdb)};DBQ=D://accdb&quot;;     //DataBase是Access MDB文件的主文件名 <br>      try{    <br>          Class.forName(&quot;sun.jdbc.odbc.JdbcOdbcDriver&quot;);    <br>          }catch(Exception e){    <br>           e.printStackTrace();    <br>       }   <br>      Connection conn=DriverManager.getConnection(sourceURL);//把驱动放入连接 <br>      Statement stmt=conn.createStatement();//创建一个 Statement 对象来将 SQL 语句发送到数据库。 <br>      stmt.executeUpdate(&quot;INSERT INTO student VALUES(&quot;+&quot;'&quot;+name+&quot;'&quot;+&quot;,&quot;+&quot;'&quot;+message+&quot;'&quot;+&quot;)&quot;); <br>      <br>      stmt.close(); <br>      conn.close(); <br>    } <br>    catch(SQLException sqle){ <br>            //System.err.println(sqle); <br>    } <br>       <br>%&gt; <!--v:3.2--> ]]></description>
<category><![CDATA[JSP]]></category>
<author><![CDATA[94164590@qq.com(木枫)]]></author>
<comments>http://94164590.qzone.qq.com/blog/1250149133#comment</comments>
<qz:effect>134218240</qz:effect>
<pubDate>Thu, 13 Aug 2009 07:38:53 GMT</pubDate>
<guid>http://94164590.qzone.qq.com/blog/1250149133</guid>
</item>

<item>
<title><![CDATA[c#自定义控件开发实例]]></title>
<link>http://94164590.qzone.qq.com/blog/1249896084</link>
<description><![CDATA[c#自定义控件开发实例 <br>  <br>源文件：<a href="http://ded.nuaa.edu.cn/download/Windows%20Extended%20Controls.rar" target="_blank">http://ded.nuaa.edu.cn/download/Windows%20Extended%20Controls.rar</a><wbr /> <br>示例代码：<a href="http://ded.nuaa.edu.cn/download/WindowsApplication6.rar" target="_blank">http://ded.nuaa.edu.cn/download/WindowsApplication6.rar</a><wbr />  <br>最近做一个图象的采集，需要一个图形的选择控件，但是在.net下没有类似vb中的shape控件，所以考虑了自己写一个控件。 <br>下面我将从头创建控件，这个控件主要是用来选择图形的Rectangle，有一下几个属性Color BorderColor：边框颜色，Color BackColor：背景颜色，bool ReSizeble：是否可移动， Rectangle SelectRectangle：选择区域。 <br>打开vs2003（我用的这个版本），新建一个c#控件库，ok，拷贝如下代码到你的代码里。using System; <br>using System.Collections; <br>using System.ComponentModel; <br>using System.Drawing; <br>using System.Data; <br>using System.Windows.Forms;namespace WindowsExtendedControls <br>{ <br> /// &lt;summary&gt; <br> /// 控件 <br> /// &lt;/summary&gt; <br> public class ShapeEx : System.Windows.Forms.Control <br> { <br>  /// &lt;summary&gt; <br>  /// 必需的设计器变量。 <br>  /// &lt;/summary&gt; <br>  ///  <br>  private Color _BorderColor=new Color(); <br>  private Color _BackColor=new Color(); <br>  private bool _ReSizeble; <br>  private Point _SelfLocation=new Point(); <br>  private Point _MouseLocation=new Point(); <br>  private int _SelfWidth; <br>  private int _SelfHeight; <br>  private int _SelectSelctedIndex;//0-8,0:SizeAll <br>  private Rectangle _rectLeftSelector=new Rectangle(); <br>  private Rectangle _rectTopSelector=new Rectangle(); <br>  private Rectangle _rectRightSelector=new Rectangle(); <br>  private Rectangle _rectBottomSelector=new Rectangle(); <br>  private Rectangle _rectLeftTopSelector=new Rectangle(); <br>  private Rectangle _rectRightTopSelector=new Rectangle(); <br>  private Rectangle _rectRightBottomSelector=new Rectangle(); <br>  private Rectangle _rectLeftBottomSelector=new Rectangle(); <br>  private System.ComponentModel.Container components = null; <br>  public ShapeEx() <br>  { <br>   // 该调用是 Windows.Forms 窗体设计器所必需的。 <br>   InitializeComponent();   // TODO: 在 InitComponent 调用后添加任何初始化 <br>  } <br>  [DefaultValue(&quot;Black&quot;),Description(&quot;边框颜色&quot;),Category(&quot;Appearance&quot;)]  <br>  public Color BorderColor <br>  { <br>   get  <br>   { <br>    // Insert code here. <br>    return _BorderColor; <br>   } <br>   set  <br>   { <br>    _BorderColor=value; <br>    this.Invalidate(); <br>   } <br>  } <br>  [DefaultValue(&quot;Control&quot;),Description(&quot;背景颜色&quot;),Category(&quot;Appearance&quot;)]  <br>  public override Color BackColor <br>  { <br>   get  <br>   { <br>    // Insert code here. <br>    return _BackColor; <br>   } <br>   set  <br>   { <br>    _BackColor=value; <br>    this.Invalidate(); <br>   } <br>  } <br>  [DefaultValue(false),Description(&quot;运行中控件大小是否可拖拽编辑&quot;),Category(&quot;Behavior&quot;)]  <br>  public  bool ReSizeble <br>  { <br>   get  <br>   { <br>    // Insert code here. <br>    return _ReSizeble; <br>   } <br>   set  <br>   { <br>    _ReSizeble=value; <br>    this.Invalidate(); <br>   } <br>  } <br>  [Description(&quot;控件选择区域&quot;),Category(&quot;Behavior&quot;)]  <br>  public  Rectangle SelectRectangle <br>  { <br>   get  <br>   { <br>    Rectangle selectRectangler=new Rectangle(); <br>    selectRectangler.X = this.Location.X+7; <br>    selectRectangler.Y = this.Location.Y+7; <br>    selectRectangler.Height = this.Height-15; <br>    selectRectangler.Width = this.Width-15; <br>    return selectRectangler; <br>   } <br>   <br>  } <br>  <br>  protected override void OnPaint(PaintEventArgs pe) <br>  { <br>   // Calling the base class OnPaint <br>   base.OnPaint(pe); <br>   ReDrawControl(pe.Graphics); <br>  } <br>  private void DrawSelector(Graphics graphics) <br>  { <br>   SolidBrush SelectorPen=new SolidBrush(Color.White); <br>   Pen borderPen=new Pen(this._BorderColor,1); <br>   try <br>   { <br>    //实心    PointF[] LeftPoints=getPointF(0,this.Height/2-3,6,6); <br>    graphics.FillClosedCurve(SelectorPen, LeftPoints);    PointF[] TopPoints=getPointF(this.Width/2-3,0,6,6); <br>    graphics.FillClosedCurve(SelectorPen, TopPoints);    PointF[] RightPoints=getPointF(this.Width-7,this.Height/2-3,6,6); <br>    graphics.FillClosedCurve(SelectorPen, RightPoints);    PointF[] BottomPoints=getPointF(this.Width/2-3,this.Height-7,6,6); <br>    graphics.FillClosedCurve(SelectorPen, BottomPoints);    PointF[] LeftTopPoints=getPointF(0,0,6,6); <br>    graphics.FillClosedCurve(SelectorPen, LeftTopPoints);    PointF[] RightTopPoints=getPointF(this.Width-7,0,6,6); <br>    graphics.FillClosedCurve(SelectorPen, RightTopPoints);    PointF[] RightBottomPoints=getPointF(this.Width-7,this.Height-7,6,6); <br>    graphics.FillClosedCurve(SelectorPen, RightBottomPoints); <br>     <br>    PointF[] LeftBottomPoints=getPointF(0,this.Height-7,6,6); <br>    graphics.FillClosedCurve(SelectorPen, LeftBottomPoints); <br>    //边框 <br>    _rectLeftSelector.X = 0; <br>    _rectLeftSelector.Y = this.Height/2-3; <br>    _rectLeftSelector.Height = 6; <br>    _rectLeftSelector.Width = 6; <br>    graphics.DrawRectangle(borderPen, _rectLeftSelector);    _rectTopSelector.X = this.Width/2-3; <br>    _rectTopSelector.Y = 0; <br>    _rectTopSelector.Height = 6; <br>    _rectTopSelector.Width = 6; <br>    graphics.DrawRectangle(borderPen, _rectTopSelector);    _rectRightSelector.X = this.Width-7; <br>    _rectRightSelector.Y = this.Height/2-3; <br>    _rectRightSelector.Height = 6; <br>    _rectRightSelector.Width = 6; <br>    graphics.DrawRectangle(borderPen, _rectRightSelector);    _rectBottomSelector.X = this.Width/2-3; <br>    _rectBottomSelector.Y = this.Height-7; <br>    _rectBottomSelector.Height = 6; <br>    _rectBottomSelector.Width = 6; <br>    graphics.DrawRectangle(borderPen, _rectBottomSelector);    _rectLeftTopSelector.X=0; <br>    _rectLeftTopSelector.Y=0; <br>    _rectLeftTopSelector.Width=6; <br>    _rectLeftTopSelector.Height=6; <br>    graphics.DrawRectangle(borderPen, _rectLeftTopSelector);    _rectRightTopSelector.X=this.Width-7; <br>    _rectRightTopSelector.Y=0; <br>    _rectRightTopSelector.Width=6; <br>    _rectRightTopSelector.Height=6; <br>    graphics.DrawRectangle(borderPen, _rectRightTopSelector);    _rectRightBottomSelector.X=this.Width-7; <br>    _rectRightBottomSelector.Y=this.Height-7; <br>    _rectRightBottomSelector.Width=6; <br>    _rectRightBottomSelector.Height=6; <br>    graphics.DrawRectangle(borderPen, _rectRightBottomSelector);    _rectLeftBottomSelector.X=0; <br>    _rectLeftBottomSelector.Y=this.Height-7; <br>    _rectLeftBottomSelector.Width=6; <br>    _rectLeftBottomSelector.Height=6; <br>    graphics.DrawRectangle(borderPen, _rectLeftBottomSelector); <br>   } <br>   catch(Exception E) <br>   { <br>    throw E; <br>   } <br>   finally <br>   { <br>    SelectorPen.Dispose(); <br>    borderPen.Dispose(); <br>   } <br>     <br>  } <br>  private void ReDrawControl(Graphics graphics) <br>  { <br>    <br>   try <br>   { <br>    <br>    //绘制背景 <br>    /* <br>    graphics.Clear(this._BackColor); <br>    SolidBrush backPen=new SolidBrush(this._BackColor); <br>    PointF point1 = new PointF(1,1); <br>    PointF point2 = new PointF(this.Width-2,1); <br>    PointF point3 = new PointF(this.Width-2,this.Height-2); <br>    PointF point4 = new PointF(1,this.Height-2); <br>    PointF[] points = {point1, point2, point3, point4}; <br>    graphics.FillClosedCurve(backPen, points); <br>    */ <br>    //绘制边框     <br>    Rectangle rectBorder=new Rectangle(); <br>    Pen borderPen=new Pen(this._BorderColor,1); <br>    rectBorder.X = 7; <br>    rectBorder.Y = 7; <br>    rectBorder.Height = this.Height-15; <br>    rectBorder.Width = this.Width-15; <br>    graphics.DrawRectangle(borderPen, rectBorder); <br>    //绘制编辑框 <br>    if (_ReSizeble) <br>    { <br>     DrawSelector(graphics); <br>    } <br>   } <br>   catch(Exception E) <br>   { <br>    throw E; <br>   } <br>   finally <br>   { <br>    graphics.Dispose(); <br>   } <br>  } <br>  /// &lt;summary&gt; <br>  /// 清理所有正在使用的资源。 <br>  /// &lt;/summary&gt; <br>  private PointF[] getPointF(int x,int y,int Width,int Height){ <br>   PointF point1 = new PointF(x,y); <br>   PointF point2 = new PointF(x+Width,y); <br>   PointF point3 = new PointF(x+Width,y+Height); <br>   PointF point4 = new PointF(x,y+Height); <br>   PointF[] points = {point1, point2, point3, point4}; <br>   return points; <br>  } <br>  protected override void Dispose( bool disposing ) <br>  { <br>   if( disposing ) <br>   { <br>    if( components != null ) <br>     components.Dispose(); <br>   } <br>   base.Dispose( disposing ); <br>  }  #region 组件设计器生成的代码 <br>  /// &lt;summary&gt; <br>  /// 设计器支持所需的方法 - 不要使用代码编辑器  <br>  /// 修改此方法的内容。 <br>  /// &lt;/summary&gt; <br>  private void InitializeComponent() <br>  { <br>   components = new System.ComponentModel.Container(); <br>   this.Resize+=new EventHandler(ShapeEx_Resize); <br>   this.MouseDown+=new MouseEventHandler(ShapeEx_MouseDown); <br>   this.MouseMove+=new MouseEventHandler(ShapeEx_MouseMove); <br>   this.MouseLeave+=new EventHandler(ShapeEx_MouseLeave); <br>   this.MouseUp+=new MouseEventHandler(ShapeEx_MouseUp);   this._BorderColor=Color.Black; <br>   this._BackColor=Color.FromName(&quot;Control&quot;); <br>   this._ReSizeble=false; <br>   this._SelectSelctedIndex=-1; <br>   SetStyle(ControlStyles.SupportsTransparentBackColor, true); <br>  } <br>  #endregion  private void ShapeEx_Resize(object sender, EventArgs e) <br>  { <br>   if (this.Width&lt;16 || this.Height&lt;16) <br>   { <br>    this.Width=16; <br>    this.Height=16; <br>   } <br>   this.Invalidate(); <br>  }  <br>  private void ShapeEx_MouseDown(object sender, MouseEventArgs e) <br>  { <br>   if (_ReSizeble) <br>   { <br>    if (_rectLeftSelector.Contains(e.X,e.Y) || _rectRightSelector.Contains(e.X,e.Y) || _rectTopSelector.Contains(e.X,e.Y) || _rectBottomSelector.Contains(e.X,e.Y) ||_rectLeftTopSelector.Contains(e.X,e.Y) || _rectRightTopSelector.Contains(e.X,e.Y) || _rectRightBottomSelector.Contains(e.X,e.Y) || _rectLeftBottomSelector.Contains(e.X,e.Y)) <br>    { <br>     if (_rectLeftTopSelector.Contains(e.X,e.Y) ) <br>     { <br>      this.Cursor=Cursors.SizeNWSE; <br>      this._SelectSelctedIndex=1; <br>     } <br>      <br>     if (_rectTopSelector.Contains(e.X,e.Y) ) <br>     { <br>      this.Cursor=Cursors.SizeNS; <br>      this._SelectSelctedIndex=2; <br>     } <br>     if (_rectRightTopSelector.Contains(e.X,e.Y) ) <br>     { <br>      this.Cursor=Cursors.SizeNESW; <br>      this._SelectSelctedIndex=3; <br>     } <br>     if (_rectRightSelector.Contains(e.X,e.Y) ) <br>     { <br>      this.Cursor=Cursors.SizeWE; <br>      this._SelectSelctedIndex=4; <br>     } <br>     if (_rectRightBottomSelector.Contains(e.X,e.Y) ) <br>     { <br>      this.Cursor=Cursors.SizeNWSE; <br>      this._SelectSelctedIndex=5; <br>     } <br>     if (_rectBottomSelector.Contains(e.X,e.Y)) <br>     { <br>      this.Cursor=Cursors.SizeNS; <br>      this._SelectSelctedIndex=6; <br>     } <br>     if (_rectLeftBottomSelector.Contains(e.X,e.Y) ) <br>     { <br>      this.Cursor=Cursors.SizeNESW; <br>      this._SelectSelctedIndex=7; <br>     } <br>     if (_rectLeftSelector.Contains(e.X,e.Y)) <br>     { <br>      this.Cursor=Cursors.SizeWE; <br>      this._SelectSelctedIndex=8; <br>     }    } <br>    else <br>    { <br>     this.Cursor=Cursors.SizeAll; <br>     this._SelectSelctedIndex=0; <br>    } <br>    this._SelfLocation.X=this.Location.X; <br>    this._SelfLocation.Y=this.Location.Y; <br>    this._MouseLocation.X=Cursor.Position.X; <br>    this._MouseLocation.Y=Cursor.Position.Y; <br>    this._SelfWidth=this.Width; <br>    this._SelfHeight=this.Height; <br>   } <br>  }  private void ShapeEx_MouseMove(object sender, MouseEventArgs e) <br>  { <br>   //move and resize <br>   switch (this._SelectSelctedIndex) <br>   { <br>    case 0: <br>     this.Location=new Point(Cursor.Position.X-(_MouseLocation.X-_SelfLocation.X),Cursor.Position.Y-(_MouseLocation.Y-_SelfLocation.Y)); <br>     break; <br>    case 1: <br>     this.Height=this._SelfHeight-(Cursor.Position.Y-_MouseLocation.Y); <br>     this.Width=this._SelfWidth-(Cursor.Position.X-_MouseLocation.X); <br>     this.Location=new Point(Cursor.Position.X-_MouseLocation.X+_SelfLocation.X,Cursor.Position.Y-_MouseLocation.Y+_SelfLocation.Y); <br>     break; <br>    case 2: <br>     this.Height=this._SelfHeight-(Cursor.Position.Y-_MouseLocation.Y); <br>     this.Location=new Point(_SelfLocation.X,Cursor.Position.Y-_MouseLocation.Y+_SelfLocation.Y); <br>     break; <br>    case 3: <br>     this.Height=this._SelfHeight-(Cursor.Position.Y-_MouseLocation.Y); <br>     this.Width=this._SelfWidth+(Cursor.Position.X-_MouseLocation.X); <br>     this.Location=new Point(_SelfLocation.X,Cursor.Position.Y-(_MouseLocation.Y-_SelfLocation.Y)); <br>     break; <br>    case 4: <br>     this.Width=this._SelfWidth+(Cursor.Position.X-_MouseLocation.X); <br>     break; <br>    case 5: <br>     this.Height=this._SelfHeight+(Cursor.Position.Y-_MouseLocation.Y); <br>     this.Width=this._SelfWidth+(Cursor.Position.X-_MouseLocation.X); <br>     break; <br>    case 6: <br>     this.Height=this._SelfHeight+(Cursor.Position.Y-_MouseLocation.Y); <br>     break; <br>    case 7: <br>     this.Height=this._SelfHeight+(Cursor.Position.Y-_MouseLocation.Y); <br>     this.Width=this._SelfWidth-(Cursor.Position.X-_MouseLocation.X); <br>     this.Location=new Point(Cursor.Position.X-_MouseLocation.X+_SelfLocation.X,_SelfLocation.Y); <br>     break; <br>    case 8: <br>     this.Width=this._SelfWidth-(Cursor.Position.X-_MouseLocation.X); <br>     this.Location=new Point(Cursor.Position.X-_MouseLocation.X+_SelfLocation.X,_SelfLocation.Y); <br>     break; <br>   }  } <br>  private void ShapeEx_MouseLeave(object sender, EventArgs e) <br>  { <br>   this.Cursor=Cursors.Default; <br>   this._SelectSelctedIndex=-1; <br>  }  private void ShapeEx_MouseUp(object sender, MouseEventArgs e) <br>  { <br>   this.Cursor=Cursors.Default; <br>   this._SelectSelctedIndex=-1; <br>  } } <br>} <br>下面讲一下控件具体如何工作，首先要写他的属性以及重写他的属性， <br>private Color _BorderColor=new Color(); <br> [DefaultValue(&quot;Black&quot;),Description(&quot;边框颜色&quot;),Category(&quot;Appearance&quot;)]  <br>  public Color BorderColor <br>  { <br>   get  <br>   { <br>    // Insert code here. <br>    return _BorderColor; <br>   } <br>   set  <br>   { <br>    _BorderColor=value; <br>    this.Invalidate(); <br>   } <br>  } <br>DefaultValue：设定默认值，Description：描述，就是属性下面的说明，Category：属性分类.其他的同理 <br>设置好属性以后应该重写他的绘制过程，也就是 <br>protected override void OnPaint(PaintEventArgs pe) <br>  { <br>   // Calling the base class OnPaint <br>   base.OnPaint(pe); <br>   ReDrawControl(pe.Graphics); <br>  } <br> private void ReDrawControl(Graphics graphics) <br>  { <br>    <br>   try <br>   { <br>    //绘制边框     <br>    Rectangle rectBorder=new Rectangle(); <br>    Pen borderPen=new Pen(this._BorderColor,1); <br>    rectBorder.X = 7; <br>    rectBorder.Y = 7; <br>    rectBorder.Height = this.Height-15; <br>    rectBorder.Width = this.Width-15; <br>    graphics.DrawRectangle(borderPen, rectBorder); <br>    //绘制编辑框 <br>    if (_ReSizeble) <br>    { <br>     DrawSelector(graphics); <br>    } <br>   } <br>   catch(Exception E) <br>   { <br>    throw E; <br>   } <br>   finally <br>   { <br>    graphics.Dispose(); <br>   } <br>  } <br> [Description(&quot;控件选择区域&quot;),Category(&quot;Behavior&quot;)]  <br>  public  Rectangle SelectRectangle <br>  { <br>   get  <br>   { <br>    Rectangle selectRectangler=new Rectangle(); <br>    selectRectangler.X = this.Location.X+7; <br>    selectRectangler.Y = this.Location.Y+7; <br>    selectRectangler.Height = this.Height-15; <br>    selectRectangler.Width = this.Width-15; <br>    return selectRectangler; <br>   } <br>   <br>  } <br>  <br>ReDrawControl中定义了Rectangle （矩形），让后填充改矩形的边框：graphics.DrawRectangle(borderPen, rectBorder);，这里要说明的是边框外面还有编辑框，所以大小不是控件的大小。DrawSelector就是绘制8个选择框的，基本和绘制边框差不多，即使定义好坐标就可以了。干好了之后不要忘了释放资源：graphics.Dispose();SelectRectangle:控件所选择的Rectangle，最终要得就是它了 <br>ok,这样一个基本的东西出来了，下面我们要写他的move和resize函数了，先添加事件: <br>this.Resize += new System.EventHandler(this.ShapeEx_Resize); <br>   this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.ShapeEx_MouseUp); <br>   this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.ShapeEx_MouseMove); <br>   this.MouseLeave += new System.EventHandler(this.ShapeEx_MouseLeave); <br>   this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.ShapeEx_MouseDown); <br>原理：当鼠标点击的时候this.MouseDown,记录鼠标的位置，控件的原始位置和大小，判断位置：_rectLeftBottomSelector.Contains(e.X,e.Y)：表示点击的是左下，设置鼠标，记录状态this._SelectSelctedIndex：判断点击了那个选择框，取值0-8：0代表移动整个控件，1是右上移动，2－8顺时针索引选择框。this.MouseMove处理如何改变控件的大小和位置 <br>case 0://只移动位置 <br>     this.Location=new Point(Cursor.Position.X-(_MouseLocation.X-_SelfLocation.X),Cursor.Position.Y-(_MouseLocation.Y-_SelfLocation.Y)); <br>     break; <br>1，5不仅移动位置，还改变大小，2，3，4，6，7，8只改变大小其他则是清理工作。 <br>好了，那么赶紧编译。生成就可以了。 <!--v:3.2--> ]]></description>
<category><![CDATA[C#]]></category>
<author><![CDATA[94164590@qq.com(木枫)]]></author>
<comments>http://94164590.qzone.qq.com/blog/1249896084#comment</comments>
<qz:effect>134218240</qz:effect>
<pubDate>Mon, 10 Aug 2009 09:21:24 GMT</pubDate>
<guid>http://94164590.qzone.qq.com/blog/1249896084</guid>
</item>

</channel>
</rss>

