<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>Web UI Design</title>
    <description></description>
    <link>http://fastwind.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>32个SEO方法提高网站的流量</title>
        <author>fastwind</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fastwind.javaeye.com">fastwind</a>&nbsp;
          链接：<a href="http://fastwind.javaeye.com/blog/228257" style="color:red;">http://fastwind.javaeye.com/blog/228257</a>&nbsp;
          发表时间: 2008年08月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>32个SEO方法提高网站的流量：&nbsp;<br /><br />1. title的重要性：Title是整个html在搜索引擎搜索结果中返回的第一要素,是最为核心的关键字词，建议不超过100个字节。&nbsp;<br /><br />2. 关键词在Meta Keywords中的使用应注意以下几点：（1） 确信使用的关键词出现在网页文本中；（2） 不要重复使用关键词；（3） 每个网页的关键词应该不一样；（4） 一个网页的关键词标签里应该包含3-5个最重要的关键词，不要超过5个；（5）主流搜索引擎对其的建议是不超过160字节。&nbsp;<br /><br />3. 关键词在Meta Description中的使用，Description：为搜索引擎提供参考，网页的描述信息；搜索引擎采纳后，作为搜索结果中的页面摘要显示，主流搜索引擎对其的建议是不超过400字节。&nbsp;<br /><br />4. 图片的关键词优化：HTML标签中，对于图片img标签有帮助的还有alt属性，这个属性可以告诉浏览器，当图片无法显示的时候，用alt属性中的值来替代。同样这个属性搜索引擎也看得到。&nbsp;<br /><br />5. 关键词在H1、H2、H3等Headline标签中的使用：H1、H2、H3等标签向搜索引擎表明他们包含的部分在整个页面的重要程度，但是应当记住：同一个页面不要出现两次及两次以上的H1、H2，否则会受到搜索引擎的惩罚。&nbsp;<br /><br />6. 关键词在页面URL中的使用： url中的关键词对搜索引擎排名中的重要作用，但是在域名中包含关键字比在目录中包含关键字拥有更大的权重，这也促使很多网站使用大量的二级域名。&nbsp;<br /><br />7. 页面内容和关键词的相关性：这一点主要是搜索引擎为了提升搜索体验，并且惩罚滥用关键字的网站，如果网页中根本没有提到，千万不要使用这样的关键词。&nbsp;<br /><br />8. 关键词在网页内容上的应用：搜索引擎推荐的关键字密度为2%-8%，这些关键字应当合理的分布在整个页面，在页面的首、尾出现关键字将受到搜索引擎的重视 。&nbsp;<br /><br />9. 如果您的网站包含动态网页（即网址中含有&ldquo;？&rdquo;字符），请务必使用SEO友好的URLs。收索引擎spiders很难索引到动态的网页。&nbsp;<br /><br />10. 网站的结构层次：搜索引擎希望站点有更简单的结构，首页除重要的企业、职位、专题及文章外，不链向具体内容页面；首页链向所有栏目；栏目及专题页面除首页外，必须链向本栏目或者专题的所有页面。&nbsp;<br /><br />11. URL中&ldquo;/&rdquo;符号的出现次数：在简化网站结构层次的同时，应当保证整站的目录层次尽量少，这样就可以具体页面少用一些/，搜索引擎对深层次的页面缺乏抓取的力度，除非该页面在首页或栏目页面有链接。&nbsp;<br /><br />12. HTML代码是否通过W3C认证：通过W3C的网页，在搜索引擎spider索引的时候，语法更为严谨，因此更能够获得指引spider进行深层次的索引。&nbsp;<br /><br />13. 导出链接的质量和相关性：链向作弊以及质量差的页面，会受到搜索引擎的连带处罚；同样，链向高质量、高相关性的页面会受到搜索引擎的喜欢。&nbsp;<br /><br />14. 外部链接的锚文字：外部链接的锚文字与页面主题密切相关的时候，搜索引擎会对该页面给予正向的评价，但是如果外部链接的锚文字与页面主题毫不相干，甚至有可能被搜索引擎惩罚。&nbsp;<br /><br />15. 外部链接页面本身的链接流行度：外部链接页面本身的链接流行度越广，该页面的权重越高，也就能够传递更多的页面权重。&nbsp;<br /><br />16. 链接的周围文字：搜索引擎（特别是Google）通过链接周围的文字进行语义分析，来判断外链页面的相关性，相关性越高则会获得更高的权重。&nbsp;<br /><br />17. 每页的最高链接应该少于100个。避免被搜索引擎视为链接农场。&nbsp;<br /><br />18. 避免链接到坏的网站，例如垃圾邮件发送者，链接农场，网络钓鱼，黑客，赌博，色情和诈骗等网站，这会严重的影响您的搜索引擎的排名。&nbsp;<br /><br />19. 外部链接页面的主题性：同样是判断页面相关性的手段。&nbsp;<br /><br />20. 外部链接页面在相关主题的网站社区中的链接流行度：用以判断外部链接页面是否采用了链接买卖等作弊手段，间接影响页面的排名。&nbsp;<br /><br />21. 外部链接网站的PR值：外部链接网站的PR值越高，代表该网站的权重越高，则能够传递更多的页面权威度。&nbsp;<br /><br />22. 验证你的CSS和HTML，检查是否有错误或已损坏的链接。&nbsp;<br /><br />23. 同域名下外部链接页面的链接流行度：用以判断外链域名网站对该页面的认可程度以及流行程度。&nbsp;<br /><br />24. 网站新外部链接产生的速率：应当平稳增长，否则可能引起搜索引擎的怀疑。&nbsp;<br /><br />25. 网站收录数量：百度的收录数量直接是网站评价等级的显示，百度按照自己的算法给每个网站评级，级别越高，显示的收录数越多，Google的搜索引擎都通用此做法。&nbsp;<br /><br />26. 用户查询的关键词与网站主题的相关性：主要是评价搜索关键词以及网站主题是否吻合，将结果正确的获得更好的排名。&nbsp;<br /><br />27. 不要让网页中包含网络诈骗，病毒，木马，间谍软体，广告软体和其他恶意程序。&nbsp;<br /><br />28. 新页面产生的速率：网站的更新速度，所有搜索引擎都喜欢更新快的站点。&nbsp;<br /><br />29. 网站的外部链接流行度、广泛度：主要是通过PR间接影响网站的排名。&nbsp;<br /><br />30. 网站的外部链接页面内容与关键词的相关性：判断链接网站之间的相关性，与防买卖链接有关。&nbsp;<br /><br />31. 网站在主题相关的网站群中的链接流行度：判断网站在所在行业的权威度。&nbsp;<br /><br />32. 网站是否通过Google Webmaster Central的确认：通过确认的站点可以向Google提供sitemap。</p>
          <br/>
          <span style="color:red;">
            <a href="http://fastwind.javaeye.com/blog/228257#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 15 Aug 2008 10:49:40 +0800</pubDate>
        <link>http://fastwind.javaeye.com/blog/228257</link>
        <guid>http://fastwind.javaeye.com/blog/228257</guid>
      </item>
      <item>
        <title>JavaFX初识</title>
        <author>fastwind</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fastwind.javaeye.com">fastwind</a>&nbsp;
          链接：<a href="http://fastwind.javaeye.com/blog/225261" style="color:red;">http://fastwind.javaeye.com/blog/225261</a>&nbsp;
          发表时间: 2008年08月07日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>Sun确实反应太慢，在Adobe Flash平台已经可以开发产品级RIA应用的时候，它给出的road map还是慢慢腾腾：&nbsp;<br /><br />2008年7月，Sun将开放JavaFX Desktop SDK&nbsp;<br />2008秋，JavaFX Desktop 1.0 发布&nbsp;<br />2009春，JavaFX Mobile and TV 1.0发布&nbsp;<br /><br />也就是说，截至今天，1.0依然在按计划进行中，我们体验的只是Preview版本（Sun也不建议用这个版本进行产品开发）,似乎让人灰心，但没关系，相信Sun可以后来居上，譬如NetBeans之于Eclipse（当然它们至今仍未分高下）。从上面也可以看出，JavaFX Desktop和JavaFX Mobile and TV 都会发布，似乎又回到了1995年时候的Sun目标。&nbsp;<br /><br />OK,先让我们来看一下JavaFX到底是什么。&nbsp;<br />JavaFX Preview SDK 是JavaFX platform的体验版本。这一版本是定位于web脚本开发人员和那些想事先体验JavaFX技术和工具的家伙。这一SDK同样包含"Nile Project"，这是一套工具和插件，能让脚本开发人员用拖放的方式建立图形化的东西。运行JavaFX Application需要：&nbsp;<br />1.Java SDK 1.6 Update 7或更新，最好是Update 10&nbsp;<br />2.JavaFX Preview SDK （上面说了，JavaFX SDK 1.0还在娘胎中），请下载Netbeans IDE 6.1 with JavaFX： http://javafx.com/htdocs/downloadpage.html&nbsp;<br />&nbsp;<br /><img src="../../../upload/picture/pic/19461/2a17403c-b689-3271-87ee-792ae8e31280.jpg" height="454" alt="" width="241" /><br />而开发JavaFX，则需要写JavaFX Script，这是一种新的脚本语言，旨在方便高效地创建图形界面及绑定数据，而这个所谓的图形界面，最终调到的是swing，但需要注意：&nbsp;<br />1.JavaFX能提供Swing所没有的一些Widgets&nbsp;<br />2.对Swing组件的的操作，使用JavaFX Script可能有所限制，也即是说，Swing里面对图形界面元素控制的一些方法或属性，在Java FX里面可能不存在。&nbsp;<br />下面是用JavaFX开发的一个Clock，其实Swing也完全可以做到：&nbsp;<br />&nbsp;<br /><img src="../../../upload/picture/pic/19463/5d1599e6-b2ce-37a1-a9bc-bd3278699142.jpg" height="323" alt="" width="293" /><br />JavaFX Script看上去：&nbsp;<br /></p>
<pre name="code" class="java">package myclockproject;  
  
import javafx.application.Frame;  
import javafx.application.Stage;  
import javafx.scene.CustomNode;  
import javafx.scene.Group;  
import javafx.scene.Node;  
import javafx.scene.geometry.Circle;  
import javafx.scene.paint.Color;  
import javafx.scene.geometry.*;  
import javafx.scene.text.Text;  
import javafx.scene.Font;  
import javafx.scene.FontStyle;  
import javafx.scene.transform.Translate;  
import javafx.scene.transform.Rotate;  
import javafx.scene.image.ImageView;  
import javafx.scene.image.Image;  
  
import java.util.Date;  
import java.lang.Math;  
import javafx.animation.Timeline;  
import javafx.animation.KeyFrame;  
import javafx.ext.swing.Button;  
  
Frame {  
  title : "Java FX Clock Application"  
  width : 295  
  height: 325  
  closeAction : function (){  
  java.lang.System.exit(0) ;  
  }  
  visible: true  
  stage: Stage {  
  content: Clock{}  
  }  
}  
  
public class Clock extends CustomNode {  
  public attribute radius : Number = 77;  
  public attribute centerX : Number = 144;  
  public attribute centerY : Number = 144;  
  public attribute hours:Number;  
  public attribute minutes:Number;  
  public attribute seconds:Number;  
  
  public function nextTick () {  
  var now = new Date();  
  seconds = now.getSeconds();  
  minutes = now.getMinutes();  
  hours = now.getHours();  
  }  
   
  public function create(): Node {  
  return Group {  
  content:[  
  ImageView {  
  image: Image {  
  url: "{__DIR__}/clock_background.png"  
  }  
  },  
   
  Group{  
  transform: Translate { x: centerX, y: centerY }  
  content: [  
  // code to display the numbers for every third hour  
  for (i in [3, 6, 9, 12])  
  Text {  
  transform: Translate { x : -5, y : 5 }  
  font: Font {size: 16 style: FontStyle.BOLD }  
  x: radius * (( i + 0 ) mod 2 * ( 2 - i / 3))  
  y: radius * (( i + 1 ) mod 2 * ( 3 - i / 3))  
  content: "{i}"  
  },  
  
  //code to display a circle for the rest of the hours on the clock  
  for (i in [1..12])  
  if (i mod 3 != 0 ) then Circle {  
  transform:Rotate { angle: 30 * i }  
  centerX: radius  
  radius: 3  
  fill: Color.BLACK  
  } else [ ],  
  Circle {  
  radius: 5  
  fill: Color.DARKRED  
  },  
  //code for the smaller center circle  
  Circle {  
  radius: 3  
  fill: Color.DARKRED  
  },  
  //code for the seconds hand  
  Line {  
  transform: Rotate { angle: bind seconds * 6 }  
  endY: -radius - 3  
  strokeWidth: 2  
  stroke: Color.RED  
  },  
  //code for the hour hand  
  Path {  
  //for the hour hands  
  transform: Rotate { angle: bind (hours + minutes / 60) * 30 - 90 }  
  fill: Color.BLACK  
  elements: [  
  MoveTo {x: 4, y: 4},  
  ArcTo {x: 4 y: -4 radiusX: 1 radiusY: 1},  
  LineTo{ x: radius - 15 y: 0},  
  ]  
  },  
  // code for the minutes hand  
  Path {  
  //for the minutes hand  
  transform: Rotate { angle: bind minutes * 6 - 90 }  
  fill: Color.BLACK  
  elements: [  
  MoveTo {x: 4, y: 4},  
  ArcTo {x: 4 y: -4 radiusX: 1 radiusY: 1},  
  LineTo{ x: radius y: 0},  
  ]  
  }]}  
  ]  
  };  
  }  
   
  init {  
  var timeline = Timeline {  
  repeatCount: Timeline.INDEFINITE  
  keyFrames : [  
  KeyFrame {  
  time : 1s  
  action: function() {  
  nextTick();  
  }  
  }  
  ]  
  }  
  timeline.start();  
   
  }  
}  </pre>
<p>&nbsp;<br /><br />JavaFX Script还是比较简单的。它与Java的差距，比JavaScript与Java的差距，个人感觉小的多。&nbsp;<br /><br />如何发布JavaFX应用呢？JavaFX内容可以通过Java Web Start发布为应用程序（这将最终运行在用户的Desktop上面），或者发布为Applets作为Java的Plug-In;无论哪种方式，都需要有一个JavaFX runtime.&nbsp;<br /><br />参考：&nbsp;<br />Sun：&nbsp;<br />http://www.sun.com/software/javafx/script/index.jsp&nbsp;<br />SUN为Java FX专题建立的网站，网站本身也是Java FX技术的一个演示。&nbsp;<br />http://javafx.com/&nbsp;<br />InfoQ:&nbsp;<br />http://www.infoq.com/news/2008/01/javafx-chet-haase&nbsp;<br />JavaFX Script：&nbsp;<br />http://www.sun.com/software/javafx/script/index.jsp</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://fastwind.javaeye.com/blog/225261#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 07 Aug 2008 09:10:42 +0800</pubDate>
        <link>http://fastwind.javaeye.com/blog/225261</link>
        <guid>http://fastwind.javaeye.com/blog/225261</guid>
      </item>
      <item>
        <title>先进的开发框架—理解什么是Spring</title>
        <author>fastwind</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fastwind.javaeye.com">fastwind</a>&nbsp;
          链接：<a href="http://fastwind.javaeye.com/blog/222787" style="color:red;">http://fastwind.javaeye.com/blog/222787</a>&nbsp;
          发表时间: 2008年08月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>一、    Spring诞生<br />Spring是一个开源框架，目前在开源社区的人气很旺，被认为是最有前途的开源框架之一。她是由Rod Johnson创建的，她的诞生是为了简化企业级系统的开发。说道Spring就不得不说EJB，因为Spring在某种意义上是EJB的替代品，她是一种轻量级的容器。用过EJB的人都知道EJB很复杂，为了一个简单的功能你不得不编写多个Java文件和部署文件，他是一种重量级的容器。也许你不了解EJB，你可能对&ldquo;轻（重）量级&rdquo;和&ldquo;容器&rdquo;比较陌生，那么这里我简单介绍一下。<br />1、什么是容器<br />&ldquo;容器&rdquo;，这个概念困扰我好久。从学习Tomcat开始就一直对此感到困惑。感性的来讲，容器就是可以用来装东西的物品。那么在编程领域就是指用来装对象（OO的思想，如果你连OO都不了解，建议你去学习OO先）的对象。然而这个对象比较特别，它不仅要容纳其他对象，还要维护各个对象之间的关系。这么讲可能还是太抽象，来看一个简单的例子：<br />代码片断1：<br /><br />
<pre name="code" class="java">public class Container  
{ 
  public void init() 
  { 
  Speaker s = new Speaker(); 
  Greeting g = new Greeting(s); 
  } 
} </pre>
&nbsp;<br /><br />可以看到这里的Container类（容器）在初始化的时候会生成一个Speaker对象和一个Greeting对象，并且维持了它们的关系，当系统要用这些对象的时候，直接问容器要就可以了。这就是容器最基本的功能，维护系统中的实例（对象）。如果到这里你还是感到模糊的话，别担心，我后面还会有相关的解释。<br /><br />2、轻量级与重量级<br />所谓&ldquo;重量级&rdquo;是相对于&ldquo;轻量级&rdquo;来讲的，也可以说&ldquo;轻量级&rdquo;是相对于重量级来讲的。在Spring出现之前，企业级开发一般都采用EJB，因为它提供的事务管理，声明式事务支持，持久化，分布计算等等都&ldquo;简化&rdquo;了企业级应用的开发。我这里的&ldquo;简化&rdquo;打了双引号，因为这是相对的。重量级容器是一种入侵式的，也就是说你要用EJB提供的功能就必须在你的代码中体现出来你使用的是EJB，比如继承一个接口，声明一个成员变量。这样就把你的代码绑定在EJB技术上了，而且EJB需要JBOSS这样的容器支持，所以称之为&ldquo;重量级&rdquo;。<br />相对而言&ldquo;轻量级&rdquo;就是非入侵式的，用Spring开发的系统中的类不需要依赖Spring中的类，不需要容器支持（当然Spring本身是一个容器），而且Spring的大小和运行开支都很微量。一般来说，如果系统不需要分布计算或者声明式事务支持那么Spring是一个更好的选择。<br /><br />二、    几个核心概念<br />在我看来Spring的核心就是两个概念，反向控制（IoC），面向切面编程（AOP）。还有一个相关的概念是POJO，我也会略带介绍。<br />1、POJO<br />我所看到过的POJO全称有两个，Plain Ordinary Java Object，Plain Old Java Object，两个差不多，意思都是普通的Java类，所以也不用去管谁对谁错。POJO可以看做是简单的JavaBean（具有一系列Getter，Setter方法的类）。严格区分这里面的概念没有太大意义，了解一下就行。<br />2、    IoC<br />IoC的全称是Inversion of Control，中文翻译反向控制或者逆向控制。这里的反向是相对EJB来讲的。EJB使用JNDI来查找需要的对象，是主动的，而Spring是把依赖的对象注入给相应的类（这里涉及到另外一个概念&ldquo;依赖注入&rdquo;，稍后解释），是被动的，所以称之为&ldquo;反向&rdquo;。先看一段代码，这里的区别就很容易理解了。<br />代码片段2：<br /><br /><br />
<pre name="code" class="java">public void greet() 
{ 
Speaker s = new Speaker(); 
s.sayHello(); 
} </pre>
&nbsp;<br /><br />代码片段3：<br /><br /><br />
<pre name="code" class="java">public void greet() 
{ 
Speaker s = (Speaker)context.lookup("ejb/Speaker"); 
s.sayHello(); 
} </pre>
&nbsp;<br /><br />代码片段4：<br /><br /><br />
<pre name="code" class="java">public class Greeting  
{ 
  public Speaker s; 
  public Greeting(Speaker s) 
  { 
  this.s = s; 
  } 
  public void greet() 
  { 
  s.sayHello(); 
  } 
} </pre>
&nbsp;<br /><br />我们可以对比一下这三段代码。其中片段2是不用容器的编码，片段3是EJB编码，片段4是Spring编码。结合代码片段1，你能看出来Spring编码的优越之处吗？也许你会觉得Spring的编码是最复杂的。不过没关系，我在后面会解释Spring编码的好处。<br />这里我想先解释一下&ldquo;依赖注入&rdquo;。根据我给的例子可以看出，Greeting类依赖Speaker类。片段2和片段3都是主动的去获取Speaker，虽然获取的方式不同。但是片段4并没有去获取或者实例化Speaker类，而是在greeting函数中直接使用了s。你也许很容易就发现了，在构造函数中有一个s被注入（可能你平时用的是，传入）。在哪里注入的呢？请回头看一下代码片段1，这就是使用容器的好处，由容器来维护各个类之间的依赖关系（一般通过Setter来注入依赖，而不是构造函数，我这里是为了简化示例代码）。Greeting并不需要关心Speaker是哪里来的或是从哪里获得Speaker，只需要关注自己分内的事情，也就是让Speaker说一句问候的话。<br />3、    AOP<br />AOP全称是Aspect-Oriented Programming，中文翻译是面向方面的编程或者面向切面的编程。你应该熟悉面向过程的编程，面向对象的编程，但是面向切面的编程你也许是第一次听说。其实这些概念听起来很玄，说到底也就是一句话的事情。<br />现在的系统往往强调减小模块之间的耦合度，AOP技术就是用来帮助实现这一目标的。举例来说，假如上文的Greeting系统含有日志模块，安全模块，事务管理模块，那么每一次greet的时候，都会有这三个模块参与，以日志模块为例，每次greet之后，都要记录下greet的内容。而对于Speaker或者Greeting对象来说，它们并不知道自己的行为被记录下来了，它们还是像以前一样的工作，并没有任何区别。只是容器控制了日志行为。如果这里你有点糊涂，没关系，等讲到具体Spring配置和实现的时候你就明白了。<br />假如我们现在为Greeting系统加入一个Valediction功能，那么AOP模式的系统结构如下：<br />G|RET|TIN|G<br />V|ALE|DIT|ION<br />|   |   |<br />日志 安全 事务<br /><br />这些模块是贯穿在整个系统中的，为系统的不同的功能提供服务，可以称每个模块是一个&ldquo;切面&rdquo;。其实&ldquo;切面&rdquo;是一种抽象，把系统不同部分的公共行为抽取出来形成一个独立的模块，并且在适当的地方（也就是切入点，后文会解释）把这些被抽取出来的功能再插入系统的不同部分。<br />从某种角度上来讲&ldquo;切面&rdquo;是一个非常形象的描述，它好像在系统的功能之上横切一刀，要想让系统的功能继续，就必须先过了这个切面。这些切面监视并拦截系统的行为，在某些（被指定的）行为执行之前或之后执行一些附加的任务（比如记录日志）。而系统的功能流程（比如Greeting）并不知道这些切面的存在，更不依赖于这些切面，这样就降低了系统模块之间的耦合度。<br /><br />三、    Spring初体验<br />这一节我用一个具体的例子Greeting，来说明使用Spring开发的一般流程和方法，以及Spring配置文件的写法。<br />首先创建一个Speaker类，你可以把这个类看做是POJO。<br />代码片段5：<br /><br /><br />
<pre name="code" class="java">public class Speaker  
{ 
  public void sayHello() 
  { 
  System.out.println("Hello!"); 
  } 
} </pre>
&nbsp;<br />再创建一个Greeting类。<br />代码片段6：<br /><br />
<pre name="code" class="java">public class Greeting  
{ 
  private Speaker speaker; 
  public void setSpeaker(Speaker speaker) 
  { 
  this.speaker = speaker; 
  } 
  public void greet() 
  { 
  speaker.sayHello(); 
  } 
} </pre>
&nbsp;<br /><br />然后要创建一个Spring的配置文件把这两个类关联起来。<br />代码片段7（applicationContext.xml）：<br /><br />&lt;"1.0" encoding="UTF-8"?&gt;&nbsp;<br />"-//SPRING//DTD BEAN//EN" &nbsp;<br />&nbsp;   "http://www.springframework.org/dtd/spring-beans.dtd"&gt;&nbsp;<br /><br /><br />&nbsp;   "Speaker" class="Speaker"&gt;&nbsp;<br />&nbsp;   "Greeting" class="Greeting"&gt;&nbsp;<br />&nbsp;       "speaker"&gt;&nbsp;<br />&nbsp;           "Speaker"/&gt;&nbsp;<br /><br /><br />要用Spring Framework必须把Spring的包加入到Classpath中，我用的是Eclipse+MyEclipse，这些工作是自动完成的。推荐用Spring的配置文件编辑器来编辑，纯手工编写很容易出错。我先分析一下这个xml文件的结构，然后再做测试。从节点开始，先声明了两个，第二个bean有一个speaker属性（property）要求被注入，注入的内容是另外一个bean Speaker。这里的命名是符合JavaBean规范的，也就是说如果是speaker属性，那么Spring容器就会调用setSpeaker()来注入这个属性。是reference的意思，表示引用另外一个bean。<br />下面看一段简单的测试代码：<br />代码片段8：<br /><br /><br />
<pre name="code" class="java">public static void main(String[] args)  
{ 
  ApplicationContext context =  
  New ClassPathXmlApplicationContext("applicationContext.xml"); 
  Greeting greeting = (Greeting)context.getBean("Greeting"); 
  greeting.greet(); 
} </pre>
&nbsp;<br /><br />这段代码很简单，如果你上文都看懂了，那么这里应该没有问题。值得注意的是Spring有两种方式来创建容器（我们不再用上文我们自己编写的Container），一种是ApplicationContext，另外一种是BeanFactory。ApplicationContext更强大一些，而且使用上两者没有太大区别，所以一般说来都用ApplicationContext。Spring容器帮助我们维护我们在配置文件中声明的Bean以及它们之间的依赖关系，我们的Bean只需要关注自己的核心业务。<br /><br />四、    面向接口的编程<br />看了这么多，也许你并没有觉得Spring给开发带来了很多便利。那是因为我举的例子还不能突出Spring的优越之处，接下来我将通过接口编程来体现Spring的强大。<br />假如现在要求扩展Greeting的功能，要让Speaker用不同的语言来问候，也就是说有不同的Speaker，比如ChineseSpeaker, EnglishSpeaker。那么对上文提到的三种编码方式（代码片段2、3、4）分别加以修改，你会发现很麻烦。假如下次又要加入一个西班牙语，又得重复劳动。很自然的会考虑到使用一个ISpeaker接口来简化工作,，更改后的代码如下（这里没有列出接口的相关代码，我想你应该明白怎么写）：        &nbsp;<br /><br />代码片段9：<br /><br />
<pre name="code" class="java">public void greet() 
{ 
ISpeaker s = new ChineseSpeaker(); 
s.sayHello(); 
} </pre>
&nbsp;<br /><br />代码片段10：<br /><br />
<pre name="code" class="java">public void greet() 
{ 
ISpeaker s = (ISpeaker)context.lookup("ejb/ChineseSpeaker"); 
s.sayHello(); 
} </pre>
&nbsp;<br /><br />代码片段11：<br /><br />
<pre name="code" class="java">public class Greeting  
{ 
  public ISpeaker s; 
  public Greet(ISpeaker s) 
  { 
  this.s = s; 
  } 
  public void greet() 
  { 
  s.sayHello(); 
  } 
} </pre>
&nbsp;<br />对比三段代码，你会发现，第一种方法还是把具体的Speaker硬编码到代码中了，第二中方法稍微好一点，但是没有本质改变，而第三种方法就不一样了，代码中并没有关于具体Speaker的信息。也就是说，如果下次还有什么改动的话，第三种方法的Greeting类是不需要修改，编译的。根据上文Spring的使用介绍，只需要改动xml文件就能给Greeting注入不同的Speaker了，这样代码的扩展性是不是提高了很多？<br />关于Spring的接口编程还有很多东西可以去挖掘，后文还会提到有关Spring Proxy的接口编程，我这里先介绍这么多，有兴趣话可以去google更多的资料。<br /><br />五、    应用Spring中的切面<br />Spring生来支持AOP，首先来看几个概念：<br />1、    切面（Aspect）：切面是系统中抽象出来的的某一个功能模块，上文已经有过介绍，这里不再多说。<br />2、    通知（Advice）：通知是切面的具体实现。也就是说你的切面要完成什么功能，具体怎么做就是在通知里面完成的。这个名称似乎有点让人费解，等后面看了代码就明白了。<br />3、    切入点（Pointcut）：切入点定义了通知应该应用到系统的哪些地方。Spring只能控制到方法（有的AOP框架可以控制到属性），也就是说你能在方法调用之前或者之后选择切入，执行额外的操作。<br />4、    目标对象（Target）：目标对象是被通知的对象。它可以是任何类，包括你自己编写的或者第三方类。有了AOP以后，目标对象就只需要关注自己的核心业务，其他的功能，比如日志，就由AOP框架支持完成。<br />5、    代理（Proxy）：简单的讲，代理就是将通知应用到目标对象后产生的对象。Spring在运行时会给每个目标对象生成一个代理对象，以后所有对目标对象的操作都会通过代理对象来完成。只有这样通知才可能切入目标对象。对系统的其他部分来说，这个过程是透明的，也就是看起来跟没用代理一样。<br />我为了简化，只介绍这5个概念。通过这几个概念应该能够理解Spring的切面编程了。如果需要深入了解Spring AOP的话再去学习其他概念也很快的。<br />下面通过一个实际的例子来说明Spring的切面编程。继续上文Greeting的例子，我们想在Speaker每次说话之前记录Speaker被调用了。<br />首先创建一个LogAdvice类：<br />代码片段12：<br /><br />
<pre name="code" class="java">public class LogAdvice implements MethodBeforeAdvice  
{ 
  public void before(Method arg0, Object[] arg1, Object arg2)throws Throwable  
  { 
  System.out.println("Speaker called!"); 
  } 
} </pre>
&nbsp;<br /><br />这里涉及到一个类，MethodBeforeAdvice，这个类是Spring类库提供的，类似的还有AfterReturningAdvice等等，从字面就能理解它们的含义。先不急着理解这个类，我稍后解释。我们继续看如何把这个类应用到我们的系统中去。<br />代码片段13：<br /><br /><br /><br />&nbsp;   "Speaker" class="Speaker"/&gt;&nbsp;<br />&nbsp;   "Greeting" class="Greeting"&gt;&nbsp;<br />&nbsp;       "speaker"&gt;&nbsp;<br />&nbsp;           "SpeakerProxy"/&gt;&nbsp;<br />&nbsp;       &nbsp;<br />&nbsp;   &nbsp;<br />&nbsp;   "LogAdvice" class="LogAdvice"/&gt;&nbsp;<br />&nbsp;   "SpeakerProxy" class="org.springframework.aop.framework.ProxyFactoryBean"&gt;&nbsp;<br />&nbsp;       "proxyInterfaces"&gt;&nbsp;<br />&nbsp;           ISpeaker&nbsp;<br />&nbsp;       &nbsp;<br />&nbsp;       "interceptorNames"&gt;&nbsp;<br />&nbsp;           &nbsp;<br />&nbsp;               LogAdvice&nbsp;<br />&nbsp;           &nbsp;<br />&nbsp;       &nbsp;<br />&nbsp;       "target"&gt;&nbsp;<br />&nbsp;           "Speaker"/&gt;&nbsp;<br />&nbsp;       &nbsp;<br />&nbsp;   &nbsp;<br /><br /><br />可以看到我们的配置文件中多了两个bean，一个LogAdvice，另外一个SpeakerProxy。LogAdvice很简单。我着重分析一下SpeakerProxy。这个Bean实际上是由Spring提供的ProxyFactoryBean实现。下面定义了三个依赖注入的属性。<br />1、    proxyInterfactes：这个属性定义了这个Proxy要实现哪些接口，可以是一个，也可以是多个（多个的话，要用list标签）。我前面讲过Proxy是在运行是动态创建的，那么这个属性就告诉Spring创建这个Proxy的时候实现哪些接口。<br />2、    interceptorNames：这个属性定义了Proxy被切入了哪些通知，这里只有一个LogAdvice。<br />3、    target：这个属性定义了被代理的对象。在这个例子中target是Speaker。<br />这样的定义实际上约束了被代理的对象必须实现一个接口，这与上文讲的面向接口的编程有点类似。其实可以这样理解，接口的定义可以让系统的其他部分不受影响，以前用ISpeaker接口来调用，现在加入了Proxy还是一样的。但实际上内容已经不一样了，以前是Speaker，现在是一个Proxy。而target属性让proxy知道具体的方法实现在哪里。Proxy可以看作是target的一个包装。当然Spring并没有强制要求用接口，通过CGLIB（一个高效的代码生成开源类库）也可以直接根据目标对象生成子类，但这种方式并不推荐。<br />我们还像以前一样的测试我们的Greeting系统，测试代码和代码片段8是一样的。运行结果如下：<br />Speaker called!<br />Hello!<br />看到效果了吧！而且你可以发现，我们加入Log功能并没有改变以前的代码，甚至测试代码都没有改变，这就是AOP的魅力所在！我们更改的只是配置文件。<br />下面解释一下刚才落下的MethodBeforeAdvice。关于这个类我并不详细介绍，因为这涉及到Spring中的另外一个概念&ldquo;连接点（Jointpoint）&rdquo;，我详细介绍一个before这个方法。这个方法有三个参数arg0表示目标对象在哪个点被切入了，既然是MethodBeforeAdvice，那当然是在Method之前被切入了。那么arg0就是表示的那个Method。第二个参数arg1是Method的参数，所以类型是Object[]。第三个参数就是目标对象了，在Greeting例子中arg2的类型实际上是Speaker。<br />在Greeting例子中，我们并没有指定目标对象的哪些方法要被切入，而是默认切入所有方法调用（虽然Speaker只有一个方法）。通过自定义Pointcut，可以控制切入点，我这里不再介绍了，因为这并不影响理解Spring AOP，有兴趣的话去google一下就知道了。<br /><br />六、实战Spring<br />虽然这部分取名为&ldquo;实战Spring&rdquo;，但实际上我并不打算在这里介绍实际开发Spring的内容，因为我写这篇文章的目的是介绍Spring的概念和用Spring开发的思路，而不是有关Spring的实践和详细介绍。文中介绍的内容和用Spring做实际开发还相去甚远。之所以取名&ldquo;实战Spring&rdquo;是我觉得理解了上文讲的内容以后，可以开始为深入学习Spring和学习如何在项目中应用Spring了。<br />要系统的学习Spring还是需要阅读一本详细介绍Spring的书，我推荐Spring in Action，因为我看的就是这本书。希望这篇文章能为你系统的学习Spring扫除一些障碍。<br /></p>
          <br/>
          <span style="color:red;">
            <a href="http://fastwind.javaeye.com/blog/222787#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 01 Aug 2008 15:15:03 +0800</pubDate>
        <link>http://fastwind.javaeye.com/blog/222787</link>
        <guid>http://fastwind.javaeye.com/blog/222787</guid>
      </item>
      <item>
        <title>java版本的escape和unescape函数</title>
        <author>fastwind</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fastwind.javaeye.com">fastwind</a>&nbsp;
          链接：<a href="http://fastwind.javaeye.com/blog/222669" style="color:red;">http://fastwind.javaeye.com/blog/222669</a>&nbsp;
          发表时间: 2008年08月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>java版本的escape和unescape函数&nbsp;<br /><br /><br />
<pre name="code" class="java"> 

class EscapeUnescape
{
 public static String escape (String src)
 {
  int i;
  char j;
  StringBuffer tmp = new StringBuffer();
  tmp.ensureCapacity(src.length()*6);

  for (i=0;i&lt;src.length() ;i++ )
  {

  j = src.charAt(i);

  if (Character.isDigit(j) || Character.isLowerCase(j) || Character.isUpperCase(j))
  tmp.append(j);
  else
  if (j&lt;256)
  {
  tmp.append( "%" );
  if (j&lt;16)
  tmp.append( "0" );
  tmp.append( Integer.toString(j,16) );
  }
  else
  {
  tmp.append( "%u" );
  tmp.append( Integer.toString(j,16) );
  }
  }
  return tmp.toString();
 }

 public static String unescape (String src)
 {
  StringBuffer tmp = new StringBuffer();
  tmp.ensureCapacity(src.length());
  int lastPos=0,pos=0;
  char ch;
  while (lastPos&lt;src.length())
  {
  pos = src.indexOf("%",lastPos);
  if (pos == lastPos)
  {
  if (src.charAt(pos+1)=='u')
  {
  ch = (char)Integer.parseInt(src.substring(pos+2,pos+6),16);
  tmp.append(ch);
  lastPos = pos+6;
  }
  else
  {
  ch = (char)Integer.parseInt(src.substring(pos+1,pos+3),16);
  tmp.append(ch);
  lastPos = pos+3;
  }
  }
  else
  {
  if (pos == -1)
  {
  tmp.append(src.substring(lastPos));
  lastPos=src.length();
  }
  else
  {
  tmp.append(src.substring(lastPos,pos));
  lastPos=pos;
  }
  }
  }
  return tmp.toString();
 }

 public static void main(String[] args) 
 {
  String tmp="~!@#$%^&amp;*()_+|\\=-,./?&gt;&lt;;'][{}\"";
  System.out.println("testing escape : "+tmp);
  tmp =escape(tmp);
  System.out.println(tmp);
  System.out.println("testing unescape :"+tmp);
  System.out.println(unescape(tmp));
 }
}</pre>
</p>
          <br/>
          <span style="color:red;">
            <a href="http://fastwind.javaeye.com/blog/222669#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 01 Aug 2008 10:54:54 +0800</pubDate>
        <link>http://fastwind.javaeye.com/blog/222669</link>
        <guid>http://fastwind.javaeye.com/blog/222669</guid>
      </item>
      <item>
        <title>javascript中的insertBefore方法</title>
        <author>fastwind</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fastwind.javaeye.com">fastwind</a>&nbsp;
          链接：<a href="http://fastwind.javaeye.com/blog/218259" style="color:red;">http://fastwind.javaeye.com/blog/218259</a>&nbsp;
          发表时间: 2008年07月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>DEMO1:<br /><br />
<pre name="code" class="html">&lt;SCRIPT LANGUAGE="JavaScript"&gt;
window.onload=function(){
  var a =document.createElement("span");
  var b =document.createTextNode("cssrain");
  a.appendChild(b);
  document.body.appendChild(a); //默认添加在文档的最后。
  //如果我们想指定位置，那么得使用insertBefore()
}&lt;/SCRIPT&gt;&lt;body&gt;
aaaaaaaaaaaaa&lt;div&gt;ccccccc&lt;/div&gt;&lt;div&gt;bbbbbbbbb&lt;/div&gt;&lt;/body&gt;</pre>
&nbsp;<br /><br /><br /><br />DEMO2:<br />
<pre name="code" class="html">&lt;SCRIPT LANGUAGE="JavaScript"&gt;
window.onload=function(){
var a =document.createElement("span");
var b =document.createTextNode("cssrain");
a.appendChild(b);
   
  var mubiao = document.getElementById("b");
  mubiao.parentNode.insertBefore(a,mubiao);
  //插入到div b 前面。
/*
parentElement.insertBefore( newElement , targetElement );
从上面语法可以看出， 父元素， 新元素，目标元素 是 insertBefore使用的3要素。
其实我们可以不管 父元素， 因为 父元素我们 可以用 目标元素.parentNode 得到。
那么insertBefore就很好用了。只要给2个参数 ： 新元素 和目标元素。

那么有没有 insertAfter()方法呢？答案看下个例子。
*/
}&lt;/SCRIPT&gt;&lt;body&gt;
aaaaaaaaaaaaa&lt;div&gt;ccccccc&lt;/div&gt;&lt;div id="b"&gt;bbbbbbbbb&lt;/div&gt;&lt;/body&gt;</pre>
&nbsp;<br /><br /><br /><br />DEMO3:<br />
<pre name="code" class="html">&lt;SCRIPT LANGUAGE="JavaScript"&gt;
// DOM没有提供insertAfter()方法，所以我们只能自己写一个。
function insertAfter(newElement,targetElement) {
  var parent = targetElement.parentNode;
  if (parent.lastChild == targetElement) {
// 如果最后的节点是目标元素，则直接添加。因为默认是最后
  parent.appendChild(newElement);
  } else {
  parent.insertBefore(newElement,targetElement.nextSibling);
//如果不是，则插入在目标元素的下一个兄弟节点 的前面。也就是目标元素的后面。
  }
}

window.onload=function(){
  var a =document.createElement("span");
  var b =document.createTextNode("cssrain");
  a.appendChild(b);
   
  var mubiao = document.getElementById("b");
  insertAfter(a,mubiao);  
}&lt;/SCRIPT&gt;&lt;body&gt;
aaaaaaaaaaaaa&lt;div&gt;ccccccc&lt;/div&gt;&lt;div id="b"&gt;bbbbbbbbb&lt;/div&gt;&lt;div&gt;dddddd&lt;/div&gt;&lt;/body&gt;</pre>
</p>
          <br/>
          <span style="color:red;">
            <a href="http://fastwind.javaeye.com/blog/218259#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 22 Jul 2008 16:24:05 +0800</pubDate>
        <link>http://fastwind.javaeye.com/blog/218259</link>
        <guid>http://fastwind.javaeye.com/blog/218259</guid>
      </item>
      <item>
        <title>关于offsetTop的疑问</title>
        <author>fastwind</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fastwind.javaeye.com">fastwind</a>&nbsp;
          链接：<a href="http://fastwind.javaeye.com/blog/217824" style="color:red;">http://fastwind.javaeye.com/blog/217824</a>&nbsp;
          发表时间: 2008年07月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;</p>
<pre name="code" class="html">&lt;body&gt;&lt;div style="border: 10px solid black;width: 640px; height: 150px;"&gt;&lt;input type="button" value="取消" onclick="alert(this.offsetTop)"/&gt;&lt;/div&gt;<br />       &lt;input type="button" value="提交"  onclick="alert(this.offsetTop)" /&gt;&lt;/body&gt; </pre>
<p>&nbsp;我现在在body里加了这样的代码，其中 &ldquo;取消&rdquo;的button在div里面，我取他的offsetTop 为什么会是 0 呢，offsetTop的定义不应该是：当前对象到其上级对象顶部的距离。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>我这里把div的border width 加成10了， &ldquo;取消&rdquo;的button的offsetTop 不应该是 10 吗？ 怎么会是0了呢？</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://fastwind.javaeye.com/blog/217824#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 22 Jul 2008 11:51:21 +0800</pubDate>
        <link>http://fastwind.javaeye.com/blog/217824</link>
        <guid>http://fastwind.javaeye.com/blog/217824</guid>
      </item>
      <item>
        <title>区分CSS中position定位属性absolute与relative</title>
        <author>fastwind</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fastwind.javaeye.com">fastwind</a>&nbsp;
          链接：<a href="http://fastwind.javaeye.com/blog/217487" style="color:red;">http://fastwind.javaeye.com/blog/217487</a>&nbsp;
          发表时间: 2008年07月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>我们都知道absolute是绝对定位，relative是相对定位，但是这个绝对与相对是什么意思呢？绝对是什么地方的绝对，相对又是相对于什么地方而言的呢？那他们又有什么样的特性，可以做出什么样的效果呢？关于两者之间又有什么样的技巧呢？下面我们就来一一解读。<br /><br />Absolute，CSS中的写法是：position:absolute; 他的意思是绝对定位，他是参照浏览器的左上角，配合TOP、RIGHT、BOTTOM、LEFT(下面简称TRBL)进行定位，在没有设定TRBL，默认依据父级的做标原始点为原始点。如果设定TRBL并且父级没有设定position属性，那么当前的absolute则以浏览器左上角为原始点进行定位，位置将由TRBL决定。<br /><br />一般来讲，网页居中的话用Absolute就容易出错，因为网页一直是随着分辨率的大小自动适应的，而Absolute则会以浏览器的左上角为原始点，不会应为分辨率的变化而变化位置。很多人出错就在于这点上出错。而网页居左其特性与Relative很相似，但是还是有本质的区别的。<br /><br />Relative，CSS中的写法是：position:relative;  他的意思是绝对相对定位，他是参照父级的原始点为原始点，无父级则以BODY的原始点为原始点，配合TRBL进行定位，当父级内有padding等CSS属性时，当前级的原始点则参照父级内容区的原始点进行定位。<br /><br /><br />有时我们还需要依靠z-index来设定容器的上下关系，数值越大越在最上面，数值范围是自然数。当然有一点要注意，父子关系是无法用z-index来设定上下关系的，一定是子级在上父级在下。</p>
<p>&nbsp;
<pre name="code" class="html">    &lt;div style="border: 10px solid black"&gt;&lt;input type="button" value="提交" style="position:relative;left:10px;top:10px" /&gt;&lt;br /&gt;&lt;input type="button" value="取消" style="position:absolute;left:10px;top:10px" /&gt;&lt;/div&gt;</pre>
&nbsp;像这样的&ldquo;提交&rdquo;button 设置了相对位置，那他就是相对于div的位置来说的，当div位置变了 button的 位置也就变了。而第二个&ldquo;取消&rdquo;button是设置了绝对位置，也就是相对于浏览器窗口的左上角的位置，他不关div怎么变化。</p>
<p>&nbsp;
<pre name="code" class="html">&lt;div style="border: 10px solid black;margin-left:100px;margin-top:100px"&gt;&lt;input type="button" value="提交" style="position:relative;left:10px;top:10px" /&gt;&lt;br /&gt;&lt;input type="button" value="取消" style="position:absolute;left:10px;top:10px" /&gt;&lt;/div&gt;</pre>
&nbsp;通过这样的一个变化就可以看出来absolute和relative的区别了。</p>
          <br/>
          <span style="color:red;">
            <a href="http://fastwind.javaeye.com/blog/217487#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 22 Jul 2008 10:08:48 +0800</pubDate>
        <link>http://fastwind.javaeye.com/blog/217487</link>
        <guid>http://fastwind.javaeye.com/blog/217487</guid>
      </item>
      <item>
        <title>对offsetLet,offsetTop,scrollLeft,scrollTop几个方法的理解 </title>
        <author>fastwind</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fastwind.javaeye.com">fastwind</a>&nbsp;
          链接：<a href="http://fastwind.javaeye.com/blog/217403" style="color:red;">http://fastwind.javaeye.com/blog/217403</a>&nbsp;
          发表时间: 2008年07月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>1.offsetTop     :<br />当前对象到其上级层顶部的距离.<br />不能对其进行赋值.设置对象到页面顶部的距离请用style.top属性.<br /><br />2.offsetLeft    :<br />当前对象到其上级层左边的距离.<br />不能对其进行赋值.设置对象到页面左部的距离请用style.left属性.<br /><br />3.offsetWidth   :<br />当前对象的宽度.<br />与style.width属性的区别在于:如对象的宽度设定值为百分比宽度,则无论页面变大还是变小,style.width都返回此百分比,而offsetWidth则返回在不同页面中对象的宽度值而不是百分比值<br /><br />4.offsetHeight :<br />与style.height属性的区别在于:如对象的宽度设定值为百分比高度,则无论页面变大还是变小,style.height都返回此百分比,而offsetHeight则返回在不同页面中对象的高度值而不是百分比值<br /><br />5.offsetParent  :<br />当前对象的上级层对象.<br />注意.如果对象是包括在一个DIV中时,此DIV不会被当做是此对象的上级层,(即对象的上级层会跳过DIV对象)上级层是Table时则不会有问题.<br />利用这个属性，可以得到当前对象在不同大小的页面中的绝对位置．<br /><br /><br />得到绝对位置脚本代码<br />&nbsp;
<pre name="code" class="js">function GetPosition(obj)
 {
  var left = 0;
  var top = 0;
 
  while(obj != document.body)
  {
  left = obj.offsetLeft;
  top = obj.offsetTop;

 obj = obj.offsetParent;
 }

 alert("Left Is : " + left + "\r\n" + "Top Is : " + top);
}</pre>
&nbsp;<br /><br />6.scrollLeft    :<br />对象的最左边到对象在当前窗口显示的范围内的左边的距离．<br />即是在出现了横向滚动条的情况下，滚动条拉动的距离．<br /><br />7.scrollTop<br />对象的最顶部到对象在当前窗口显示的范围内的顶边的距离．<br />即是在出现了纵向滚动条的情况下，滚动条拉动的距离．<br /><br /></p>
          <br/>
          <span style="color:red;">
            <a href="http://fastwind.javaeye.com/blog/217403#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 22 Jul 2008 00:51:25 +0800</pubDate>
        <link>http://fastwind.javaeye.com/blog/217403</link>
        <guid>http://fastwind.javaeye.com/blog/217403</guid>
      </item>
      <item>
        <title>一个可以拖拽的DIV</title>
        <author>fastwind</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fastwind.javaeye.com">fastwind</a>&nbsp;
          链接：<a href="http://fastwind.javaeye.com/blog/217395" style="color:red;">http://fastwind.javaeye.com/blog/217395</a>&nbsp;
          发表时间: 2008年07月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;</p>
<pre name="code" class="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;head&gt;&lt;title&gt;&lt;/title&gt;&lt;/head&gt;&lt;body&gt;&lt;div style="background: #99CCFF; height: 140px; width: 180px; border: 1px solid #206100"
        class="dragdiv"&gt;&lt;/div&gt;&lt;div style="background: #99CCFF; height: 140px; width: 180px; border: 1px solid #206100"
        class="dragdiv"&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;&lt;script type="text/javascript"&gt;
var Drag={

    dragged:false,
	ao:null,
	
    dragStart:function()
    {
        Drag.ao=event.srcElement;
        Drag.dragged=true;
        Drag.ao.style.position="absolute";
        Drag.ao.style.filter="alpha(opacity=70)";
        Drag.ao.style.cursor="move";
        Drag.ao.style.border="1px dashed red";
		Drag.lastX=event.clientX;               //自定义属性
		Drag.lastY=event.clientY;
		Drag.lastLeft=Drag.ao.offsetLeft;
		Drag.lastTop=Drag.ao.offsetTop;
    },
    draging:function(){//判断MOUSE的位置
		if(!Drag.dragged||Drag.ao==null)return;
		var tX=event.clientX;
		var tY=event.clientY;
		Drag.ao.style.left=parseInt(Drag.lastLeft)+tX-Drag.lastX;
		Drag.ao.style.top=parseInt(Drag.lastTop)+tY-Drag.lastY;
		},
    dragEnd:function(){
		if(!Drag.dragged)
			return;
		Drag.dragged=false;
		Drag.ao.style.border="1px solid #206100";
		Drag.ao.style.filter="";
	},
    
    init:function()
    {
        var dragdiv=document.getElementsByTagName('div');
        for(var i=0;i&lt;dragdiv.length;i++)
        {
            if(dragdiv[i].className=="dragdiv")
            {
                dragdiv[i].attachEvent("onmousedown",Drag.dragStart);
            }
        }
        document.onmousemove=Drag.draging;
		document.onmouseup=Drag.dragEnd;
    }
};

Drag.init();&lt;/script&gt;</pre>
<p>&nbsp;</p>
<p>&nbsp;拖拽其实并不是很难的东西，可是这个我也是弄了半天才弄出来的，其中的主要原因就是坐标的问题，关于offsetTop clientX ，都是比较棘手的</p>
<p>&nbsp;</p>
<p>&nbsp;
<pre name="code" class="html">Drag.ao.style.left=parseInt(Drag.lastLeft)+tX-Drag.lastX;
Drag.ao.style.top=parseInt(Drag.lastTop)+tY-Drag.lastY;</pre>
</p>
<p>这里我理解了好长的时间，如果没有加上parseInt(Drag.lastLeft)，则当移动的时候div初始是定位在document.body的坐上角的，然后进行拖拽，div才能按正常的轨道滑行，而加上parseInt(Drag.lastLeft)了，在div移动初始的时候会把相对于document.body的坐标也加上去了， 这样就感觉到是当前位置的移动。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://fastwind.javaeye.com/blog/217395#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 22 Jul 2008 00:05:47 +0800</pubDate>
        <link>http://fastwind.javaeye.com/blog/217395</link>
        <guid>http://fastwind.javaeye.com/blog/217395</guid>
      </item>
      <item>
        <title>CSS中background的用法</title>
        <author>fastwind</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fastwind.javaeye.com">fastwind</a>&nbsp;
          链接：<a href="http://fastwind.javaeye.com/blog/216630" style="color:red;">http://fastwind.javaeye.com/blog/216630</a>&nbsp;
          发表时间: 2008年07月20日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          CSS中  background 是一个很基本的而且比较常用的样式<br /><br />background : background-color || background-image || background-repeat || background-attachment || background-position <br /><br />这个是 background 的几个参数，这些参数并不是都要写上的。<br /><br />background-color： 背景颜色，这里可以写英文，可以写RGB，可以写#xxxxxx<br />                   transparent : 　背景色透明<br /><br />background-image：背景图片，只能写 none 或者 url (url) <br /><br />background-repeat：背景图象的平铺<br />                   repeat : 　背景图像在纵向和横向上平铺<br />                   no-repeat : 　背景图像不平铺<br />                   repeat-x : 　背景图像在横向上平铺<br />                   repeat-y : 　背景图像在纵向平铺 <br /><br />background-attachment：背景图象的流动性<br />                       scroll : 　背景图像是随对象内容滚动<br />                       fixed : 　背景图像固定<br /><br />background-position ：背景图象的位置<br />                      length : 　百分数 | 由浮点数字和单位标识符组成的长度值。 <br />                      position : 　top | center | bottom | left | center | right <br /><br />background-position 这个参数很有意思，一般可能很少人用到，不过这个参数理解好了，确实有很大的用处，首先background-position有2个参数：background-position:(X Y),这个一般有2种情况，一个是div比背景图片大，则用这个属性背景图片会在div里浮动，如div比背景图片小，那么就变成了背景图片的变幻，具体的用代码说明吧。<br /><br />这个是做的一个圆角的div，<br />&lt;div style="width:700px"><br />    &lt;div style="padding-left:8px; background:transparent url(img/corners.gif) no-repeat;"><br />        &lt;div style="background:transparent url(img/corners.gif) no-repeat right -8px; padding-right:8px;"><br />            &lt;div style="height:8px;background:transparent url(img/tb.gif) repeat-x 0 0;" >&lt;/div><br />        &lt;/div><br />    &lt;/div><br />    &lt;div style="padding-left:4px; background:transparent url(img/l.gif) repeat-y;"><br />        &lt;div style="padding-right:4px;background:transparent url(img/r.gif) repeat-y right;"><br />            &lt;div style="background:#eee url(img/tb.gif) repeat-x 0 -16px;">fdsafasdfasd&lt;br />fdsafasdfasdfasdf&lt;br />fdsafasdfasdfasdf&lt;br />fdsafasdfasdfasdf&lt;br />fdsafasdfasdfasdf&lt;br />fdsafasdfasdfasdf&lt;br />fdsafasdfasdfasdf&lt;br />fdsafasdfasdfasdf&lt;br />fdsafasdfasdfasdf&lt;br />fdsafasdfasdfasdf&lt;/div><br />        &lt;/div><br />    &lt;/div><br />    &lt;div style="padding-left:8px; background:transparent url(img/corners.gif) no-repeat 0 -16px;"><br />        &lt;div style="background:transparent url(img/corners.gif) no-repeat right -24px; padding-right:8px;"><br />            &lt;div style="height:8px;background:transparent url(img/tb.gif) repeat-x 0 -8px;" >&lt;/div><br />        &lt;/div><br />    &lt;/div><br />&lt;/div>
          <br/>
          <span style="color:red;">
            <a href="http://fastwind.javaeye.com/blog/216630#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 20 Jul 2008 01:29:18 +0800</pubDate>
        <link>http://fastwind.javaeye.com/blog/216630</link>
        <guid>http://fastwind.javaeye.com/blog/216630</guid>
      </item>
      <item>
        <title>CSS中的display:none和visibility:hidden的区别 </title>
        <author>fastwind</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fastwind.javaeye.com">fastwind</a>&nbsp;
          链接：<a href="http://fastwind.javaeye.com/blog/216234" style="color:red;">http://fastwind.javaeye.com/blog/216234</a>&nbsp;
          发表时间: 2008年07月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>二者都是隐藏HTML元素，在视觉效果上没有区别，但在一些DOM操作中二者还是有所不同的。<br />display:none;<br />使用该属性后，HTML元素（对象）的宽度、高度等各种属性值都将&ldquo;丢失&rdquo;;<br />visibility:hidden;<br />使用该属性后，HTML元素（对象）仅仅是在视觉上看不见（完全透明），而它所占据的空间位置仍然存在，也即是说它仍具有高度、宽度等属性值。<br /><br />具体区别请看演示代码吧：&nbsp;<br />&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;<br />&lt;html xmlns="http://www.w3.org/1999/xhtml" lang="gb2312"&gt;<br />&lt;head&gt;<br />&lt;head&gt;<br />&lt;title&gt; 实例演示：CSS中的display:none和visible:hidden的区别 &lt;/title&gt;<br />&lt;meta http-equiv="content-type" content="text/html; charset=gb2312" /&gt;<br />&lt;meta http-equiv="content-type" content="text/html; charset=gb2312" /&gt;<br />&lt;meta name="author" content="枫岩,CnLei.y.l@gmail.com"&gt;<br />&lt;meta name="copyright" content="http://www.cnlei.com" /&gt;<br />&lt;/head&gt;<br />&lt;body&gt;<br />&lt;p&gt;&lt;a href="javascript:alert($('CnLei_1').innerHTML+'的宽度:\n'+GetXYWH($('CnLei_1')).W);"&gt;点击这里 display:none;&lt;/a&gt;&lt;/p&gt;<br />&lt;p&gt;&lt;a href="javascript:alert($('CnLei_2').innerHTML+'的宽度:\n'+GetXYWH($('CnLei_2')).W);"&gt;点击这里 visibility:hidden;&lt;/a&gt;&lt;/p&gt;<br />&lt;div id="CnLei_1" style="display:none;"&gt;CnLei_1&lt;/div&gt;<br />&lt;div id="CnLei_2" style="visibility:hidden;"&gt;CnLei_2&lt;/div&gt;<br /><br />&lt;script type="text/javascript"&gt;<br />var w3c=(document.getElementById)? true: false;<br />var agt=navigator.userAgent.toLowerCase();<br />var ie = ((agt.indexOf("msie") != -1) &amp;&amp; (agt.indexOf("opera") == -1) &amp;&amp; (agt.indexOf("omniweb") == -1));<br />var ie5=(w3c &amp;&amp; ie)? true : false;<br />var ns6=(w3c &amp;&amp; (navigator.appName=="Netscape"))? true: false;<br /><br />function $(o){<br />return document.getElementById(o)?document.getElementById(o):o;<br />}<br /><br />function GetXYWH(o){<br />&nbsp;var o=$(o);<br />&nbsp;var nLt=0;<br />&nbsp;var nTop=0;<br />&nbsp;var offsetParent = o;<br />&nbsp;while (offsetParent!=null &amp;&amp; offsetParent!=document.body) {<br />&nbsp;nLt+=offsetParent.offsetLeft;<br />&nbsp;nTop+=offsetParent.offsetTop;<br />&nbsp;if(!ns6){<br />&nbsp;parseInt(offsetParent.currentStyle.borderLeftWidth)&gt;0?nLt+=parseInt(offsetParent.currentStyle.borderLeftWidth):"";<br />&nbsp;parseInt(offsetParent.currentStyle.borderTopWidth)&gt;0?nTop+=parseInt(offsetParent.currentStyle.borderTopWidth):"";<br />&nbsp;}<br />&nbsp;offsetParent=offsetParent.offsetParent;<br />&nbsp;}<br />&nbsp;return {X:nLt,Y:nTop,W:o.offsetWidth,H:o.offsetHeight};<br />}<br />&lt;/script&gt;<br />&lt;/body&gt;<br />&lt;/html&gt;<br /></p>
          <br/>
          <span style="color:red;">
            <a href="http://fastwind.javaeye.com/blog/216234#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 18 Jul 2008 16:09:52 +0800</pubDate>
        <link>http://fastwind.javaeye.com/blog/216234</link>
        <guid>http://fastwind.javaeye.com/blog/216234</guid>
      </item>
      <item>
        <title>confirm的用法javascript confirm </title>
        <author>fastwind</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fastwind.javaeye.com">fastwind</a>&nbsp;
          链接：<a href="http://fastwind.javaeye.com/blog/216228" style="color:red;">http://fastwind.javaeye.com/blog/216228</a>&nbsp;
          发表时间: 2008年07月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>confirm函数&nbsp;<br /><br />confirm函数用于提供确认功能，它首先显示给定的message参数所包含的信息，并提供两个可选择的回答&ldquo;ok&rdquo;和&ldquo;cancel&rdquo;，然后等待用户选择其中的一个。如果用户选择&ldquo;ok&rdquo;则返回true；否则，如若选择&ldquo;cancel&rdquo;则返回false。该函数的语法格式如下：<br /><br />window.confirm (message, ok, cancel)<br /><br />它有3个参数，其中参数message是欲显示的字符串形式的提示信息；参数ok也是用于显示的一个字符串信息，它可以是&ldquo;OK&rdquo;，也可以是其他表示OK意义的文本信息，如&ldquo;I Agree&rdquo;、&ldquo;I Like&rdquo;等等；同样，参数cancel也是用于显示的字符串信息，可以是&ldquo;Cancel&rdquo;文本，也可以是其他表示Cancel意义的文本信息。<br /><br />&lt;script&gt;<br />var bln = window.confirm("确定吗?");<br />alert(bln)<br />&lt;/script&gt;<br /><br />或<br />Button.Attributes.Add("onclick", "javascript:if(!confirm('你确定要删除该系统咨询吗？')) { return false; }")<br /><br />Button.Attributes.Add("onclick","javascript:return confirm('请在登陆后运行，是否现在重新登陆？')")<br /><br />例如：&lt;a onclick="javascript:if(!confirm('确定要删除选择的信息吗？\n此操作不可以恢复！')) { return false; }"   href="delhtml.asp?adid=&lt;%=rs("adid")%&gt;&amp;type_oneid=&lt;%=rs("type_oneid")%&gt;"&gt;&lt;font color="green"&gt;删除&lt;/font&gt;&lt;/a&gt;<br /><br /><br />例子：<br /><br />以下放在&lt;head&gt;&lt;/head&gt;中<br /><br />&lt;script&gt;&nbsp;<br /><br />function rusure()<br /><br />{ &nbsp;<br /><br />question = confirm("确实要去进入吗?") &nbsp;<br /><br />if (question !="0")<br /><br />{<br /><br />window.open("","测试公告窗口","width=340,height=163,toolbar=0,status=0,menubar=0,resize=0");<br /><br />}&nbsp;<br /><br />}&nbsp;<br /><br />&lt;/script&gt;<br /><br />以下放在&lt;body&gt;&lt;/body&gt;中<br /><br />&lt;a href="" onClick="rusure() ;return false;"&gt;来点击我&lt;/a&gt;<br /><br /><br />用confirm确认提交动作，提交确认提示<br /><br /><br />例如在留言簿点击重写时，有时候我们希望会有一个提示，以免失误操作。代码如下：<br />　　<br />方法一<br /><br />&lt;input name="Submit" type="submit" onClick="if(confirm('是否打开网页？')) location='http://www.05376.com'" value="打开"&gt;<br /><br />　　方法二<br /><br />&lt;input name="Reset" type="reset" onClick="return clearbutton()" value="重写"&gt;<br />&lt;script type="text/javascript"&gt;<br />function clearbutton()<br />{<br />if (!confirm("确定要重写吗？")) return false;<br />}<br /><br /></p>
          <br/>
          <span style="color:red;">
            <a href="http://fastwind.javaeye.com/blog/216228#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 18 Jul 2008 15:56:15 +0800</pubDate>
        <link>http://fastwind.javaeye.com/blog/216228</link>
        <guid>http://fastwind.javaeye.com/blog/216228</guid>
      </item>
      <item>
        <title>CSS filter滤镜的用法 </title>
        <author>fastwind</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fastwind.javaeye.com">fastwind</a>&nbsp;
          链接：<a href="http://fastwind.javaeye.com/blog/216197" style="color:red;">http://fastwind.javaeye.com/blog/216197</a>&nbsp;
          发表时间: 2008年07月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;</p>
<p>&nbsp;</p>
<p>filter:filtername(parameters)　即 filter:滤镜名称（参数）</p>
<p>滤镜效果 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 功能描述&nbsp;<br />Alpha  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;设置不同的透明度变化效果&nbsp;<br />Blur &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 建立模糊效果&nbsp;<br />DropShadow &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 建立一种偏移的影象轮廓，即投射阴影&nbsp;<br />FlipH &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;水平翻转&nbsp;<br />FlipV &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;垂直翻转&nbsp;<br />Glow &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;为对象的边界增加色彩光效&nbsp;<br />Gray &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 将图片以灰度形式显示&nbsp;<br />Invert &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;将色彩、饱和度以及亮度值完全反转,类似底片效果&nbsp;<br />Light &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;在一个对象上进行灯光投影&nbsp;<br />Mask &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;为一个对象建立彩色透明遮罩&nbsp;<br />Shadow &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 为对象建立轮廓的影效果&nbsp;<br />Wave &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在X轴和Y轴方向利用正弦波打乱图片&nbsp;<br />Xray &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 只显示对象的轮廓&nbsp;<br /><br />具体的应用有两种方法：<br /><br />1、 先定义好CSS ，再在页面中需要的对象上使用预先定义好的CSS，实际上CSS的设置对话框里已经预先将这些滤镜的语法设置好了，我们只需填上适合的具体参数即可：<br /><br />　　2、直接在支持CSS滤镜效果的HTML控件元素上编写CSS filter代码。<br /><br />a.Alpha 滤镜<br /><br />　　"Alpha"属性是把一个目标元素与背景混合。设计者可以指定数值来控制混合的程度。这种&ldquo;与背景混合&rdquo;通俗地说就是一个元素的透明度。通过指定坐标，可以指定各种不同范围的透明度。<br />Alpha 滤镜语法 {FILTER：ALPHA(opacity=opacity,finishopacity=finishopacity,<br />style=style,startx=startx,<br />starty=starty,finishx=finishx,finishy=finishy)}&nbsp;<br /><br />　　参数含义分别如下：<br /><br />参数  说明&nbsp;<br />opacity 透明度。默认的范围是从0 到 100，他们其实是百分比的形式。也就是说，0代表完全透明，100代表完全不透明。&nbsp;<br />finishopacity 是一个可选参数，如果想要设置渐变的透明效果，就可以使用他们来指定结束时的透明度。范围也是0 到 100。&nbsp;<br />style 指定透明区域的形状特征：<br />0 代表统一形状<br />1 代表线形<br />2 代表放射状<br />3 代表矩形&nbsp;<br />startx 渐变透明效果开始处的 X坐标。&nbsp;<br />starty 渐变透明效果开始处的 Y坐标。&nbsp;<br />finishx 渐变透明效果结束处的 X坐标。&nbsp;<br />finishy 渐变透明效果结束处的 Y坐标。&nbsp;<br />b.Blur 滤镜　　用手指在一幅尚未干透的画面迅速划过时，画面就会变得模糊。&rdquo;Blur"就是产生同样的模糊效果。<br /><br />Blur滤镜语法 HTML：{filter:blur(add=add,direction=direction,<br />strength=strength)}<br />Script语言： [oblurfilter=] object.filters.blur&nbsp;<br /><br />　　参数含义分别如下：<br /><br />参数  说明&nbsp;<br />add 它指定图片是否被改变成印象派的模糊效果。模糊效果是按顺时针的方向进行的，<br />这是一个布尔值:ture （默认）或false&nbsp;<br />direction 该参数用来设置模糊的方向。<br />0度代表垂直向上，每45度为一个单位，默认值是向左的270度&nbsp;<br />strength 只能使用整数来指定，代表有多少像素的宽度将受到模糊影响，默认是5个像素。&nbsp;<br /><br />c.DropShadow 滤镜&nbsp;<br /><br />　　&ldquo;DropShaow"，顾名思义就是添加对象的阴影效果。其工作原理是建立一个偏移量，加上色彩。&nbsp;<br /><br />DropShadow 滤镜语法 {filter:dropshadow<br />(color=color,offx=ofx,offy=offy,positive=positive)}&nbsp;<br /><br />　　参数含义如下：<br /><br />参数  说明&nbsp;<br />Color 代表投射阴影的颜色&nbsp;<br />offx X方向阴影的偏移量&nbsp;<br />offy Y方向阴影的偏移量&nbsp;<br />Positive 布尔值<br />如果为TRUE（非0），就为任何的非透明像素建立可见的投影<br />如果为FASLE（0），就为透明的像素部分建立透明效果&nbsp;<br /><br />d.FlipH, FlipV 滤镜<br /><br />　　FlipH 滤镜实现水平反转 FlipH 滤镜语法 {filter:filph}&nbsp;<br /><br />　　FlipV 滤镜实现垂直反转&nbsp;<br /><br />FlipV 滤镜语法 {filter:filpv}&nbsp;<br />e.FlipH, FlipV 滤镜<br /><br />　　FlipH 滤镜实现水平反转 FlipH 滤镜语法 {filter:filph}&nbsp;<br /><br />　　FlipV 滤镜实现垂直反转&nbsp;<br /><br />FlipV 滤镜语法 {filter:filpv}&nbsp;<br />f.Glow 滤镜<br /><br />　　对一个对象使用"glow"属性后，这个对象的边缘就会产生类似发光的效果。<br /><br />Glow 滤镜语法 {filter:glow(color=color,strength)}&nbsp;<br /><br />　　参数含义如下：<br /><br />参数  说明&nbsp;<br />Color 指定发光的颜色&nbsp;<br />STRENGTH 强度，值为1到255之间的任何整数，指定发光色力度和范围。&nbsp;<br />g.Gray ,Invert,Xray 滤镜<br /><br />　　使用Gray滤镜可以把一张图片变成灰度图，语法很简单：<br /><br />Gray 滤镜语法 {filter:gray}&nbsp;<br />h.Gray ,Invert,Xray 滤镜<br /><br />　　使用Gray滤镜可以把一张图片变成灰度图，语法很简单：<br /><br />Gray 滤镜语法 {filter:gray}&nbsp;<br />i.Mask 滤镜<br />Mask 滤镜语法 {filter:mask(color=color)}&nbsp;<br /><br />　　使用"MASK"属性可以为对象建立一个覆盖于表面的膜，其效果就象戴着有色眼镜看物体一样 。<br />j.<br /><br />Light 滤镜<br /><br /><br />Light 滤镜语法 {filter:light}&nbsp;<br /><br /><br />　　这个属性模拟光源的投射效果。一旦为对象定义了&ldquo;LIGHT"滤镜属性，那么就可以调用它的&ldquo;方法(Method)"来设置或者改变属性。&ldquo;LIGHT"可用的方法有：<br /><br /><br />参数  说明&nbsp;<br />AddAmbient  加入包围的光源&nbsp;<br />AddCone 加入锥形光源&nbsp;<br />AddPoint 加入点光源&nbsp;<br />Changcolor  改变光的颜色&nbsp;<br />Changstrength 改变光源的强度&nbsp;<br />Clear 清除所有的光源&nbsp;<br />MoveLight 移动光源&nbsp;<br /><br /><br />k.Shadow 滤镜<br />Shadow 滤镜<br />语法 {filter:shadow(color=color,direction=direction)}&nbsp;<br /><br />　　利用&ldquo;Shadow&rdquo;属性可以在指定的方向建立物体的投影，COLOR是投影色，DIRECTION是设置投影的方向。其中0度代表垂直向上，然后每45度为一个单位。它的默认值是向左的270度。<br />l.<br /><br />Wave 滤镜<br /><br /><br />Wave 滤镜<br />语法 {filter:wave(add=add,freq=freq,<br />lightstrength=strength,<br />phase=phase,strength=strength)}&nbsp;<br /><br />参数  说明&nbsp;<br />wave 把对象按垂直的波形样式打乱。<br />默认是 TRUE（非0）&nbsp;<br />ADD 是否要把对象按照波形样式打乱&nbsp;<br />FREQ 波纹的频率，也就是指定在对象上一共需要产生多少个完整的波纹&nbsp;<br />LIGHTSTRENGTH 可以对于波纹增强光影的效果，范围0----100&nbsp;<br />PHASE 设置正弦波的偏移量&nbsp;<br />STRENGTH 振幅大小&nbsp;<br /><br /><br />m.Gray ,Invert,Xray 滤镜<br /><br />　　使用Gray滤镜可以把一张图片变成灰度图，语法很简单：<br /><br />Gray 滤镜语法 {filter:gray}</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://fastwind.javaeye.com/blog/216197#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 18 Jul 2008 15:30:42 +0800</pubDate>
        <link>http://fastwind.javaeye.com/blog/216197</link>
        <guid>http://fastwind.javaeye.com/blog/216197</guid>
      </item>
      <item>
        <title>Convert用法</title>
        <author>fastwind</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fastwind.javaeye.com">fastwind</a>&nbsp;
          链接：<a href="http://fastwind.javaeye.com/blog/215729" style="color:red;">http://fastwind.javaeye.com/blog/215729</a>&nbsp;
          发表时间: 2008年07月17日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>sql server使用convert来取得datetime日期数据，以下实例包含各种日期格式的转换<br />语句及查询结果：<br />Select CONVERT(varchar(100), GETDATE(), 0): 05 16 2006 10:57AM<br />Select CONVERT(varchar(100), GETDATE(), 1): 05/16/06<br />Select CONVERT(varchar(100), GETDATE(), 2): 06.05.16<br />Select CONVERT(varchar(100), GETDATE(), 3): 16/05/06<br />Select CONVERT(varchar(100), GETDATE(), 4): 16.05.06<br />Select CONVERT(varchar(100), GETDATE(), 5): 16-05-06<br />Select CONVERT(varchar(100), GETDATE(), 6): 16 05 06<br />Select CONVERT(varchar(100), GETDATE(), 7): 05 16, 06<br />Select CONVERT(varchar(100), GETDATE(), 8): 10:57:46<br />Select CONVERT(varchar(100), GETDATE(), 9): 05 16 2006 10:57:46:827AM<br />Select CONVERT(varchar(100), GETDATE(), 10): 05-16-06<br />Select CONVERT(varchar(100), GETDATE(), 11): 06/05/16<br />Select CONVERT(varchar(100), GETDATE(), 12): 060516<br />Select CONVERT(varchar(100), GETDATE(), 13): 16 05 2006 10:57:46:937<br />Select CONVERT(varchar(100), GETDATE(), 14): 10:57:46:967<br />Select CONVERT(varchar(100), GETDATE(), 20): 2006-05-16 10:57:47<br />Select CONVERT(varchar(100), GETDATE(), 21): 2006-05-16 10:57:47.157<br />Select CONVERT(varchar(100), GETDATE(), 22): 05/16/06 10:57:47 AM<br />Select CONVERT(varchar(100), GETDATE(), 23): 2006-05-16<br />Select CONVERT(varchar(100), GETDATE(), 24): 10:57:47<br />Select CONVERT(varchar(100), GETDATE(), 25): 2006-05-16 10:57:47.250<br />Select CONVERT(varchar(100), GETDATE(), 100): 05 16 2006 10:57AM<br />Select CONVERT(varchar(100), GETDATE(), 101): 05/16/2006<br />Select CONVERT(varchar(100), GETDATE(), 102): 2006.05.16<br />Select CONVERT(varchar(100), GETDATE(), 103): 16/05/2006<br />Select CONVERT(varchar(100), GETDATE(), 104): 16.05.2006<br />Select CONVERT(varchar(100), GETDATE(), 105): 16-05-2006<br />Select CONVERT(varchar(100), GETDATE(), 106): 16 05 2006<br />Select CONVERT(varchar(100), GETDATE(), 107): 05 16, 2006<br />Select CONVERT(varchar(100), GETDATE(), 108): 10:57:49<br />Select CONVERT(varchar(100), GETDATE(), 109): 05 16 2006 10:57:49:437AM<br />Select CONVERT(varchar(100), GETDATE(), 110): 05-16-2006<br />Select CONVERT(varchar(100), GETDATE(), 111): 2006/05/16<br />Select CONVERT(varchar(100), GETDATE(), 112): 20060516<br />Select CONVERT(varchar(100), GETDATE(), 113): 16 05 2006 10:57:49:513<br />Select CONVERT(varchar(100), GETDATE(), 114): 10:57:49:547<br />Select CONVERT(varchar(100), GETDATE(), 120): 2006-05-16 10:57:49<br />Select CONVERT(varchar(100), GETDATE(), 121): 2006-05-16 10:57:49.700<br />Select CONVERT(varchar(100), GETDATE(), 126): 2006-05-16T10:57:49.827<br />Select CONVERT(varchar(100), GETDATE(), 130): 18 ???? ?????? 1427 10:57:49:907AM<br />Select CONVERT(varchar(100), GETDATE(), 131): 18/04/1427 10:57:49:920AM<br /><br />说明:<br />使用 CONVERT：<br /><br />CONVERT ( data_type [ ( length ) ] , expression [ , style ] )<br /><br />参数<br />expression<br /><br />是任何有效的 Microsoft&reg; SQL Server&trade; 表达式。。<br /><br />data_type<br /><br />目标系统所提供的数据类型，包括 bigint 和 sql_variant。不能使用用户定义的数据类型。<br />length<br /><br />nchar、nvarchar、char、varchar、binary 或 varbinary 数据类型的可选参数。<br /><br />style<br /><br />日期格式样式，借以将 datetime 或 smalldatetime 数据转换为字符数据（nchar、nvarchar、char、varchar、nchar 或 nvarchar 数据类型）;或者字符串格式样式，借以将 float、real、money 或 smallmoney 数据转换为字符数据（nchar、nvarchar、char、varchar、nchar 或 nvarchar 数据类型）。<br /><br />SQL Server 支持使用科威特算法的阿拉伯样式中的数据格式。<br /><br />在表中，左侧的两列表示将 datetime 或 smalldatetime 转换为字符数据的 style 值。给 style 值加 100，可获得包括世纪数位的四位年份 (yyyy)。<br /><br />不带世纪数位 (yy) 带世纪数位 (yyyy)&nbsp;<br />标准&nbsp;<br />输入/输出**&nbsp;<br />- 0 或 100 (*) 默认值 mon dd yyyy hh:miAM（或 PM）&nbsp;<br />1 101 美国 mm/dd/yyyy&nbsp;<br />2 102 ANSI yy.mm.dd&nbsp;<br />3 103 英国/法国 dd/mm/yy&nbsp;<br />4 104 德国 dd.mm.yy&nbsp;<br />5 105 意大利 dd-mm-yy&nbsp;<br />6 106 - dd mon yy&nbsp;<br />7 107 - mon dd, yy&nbsp;<br />8 108 - hh:mm:ss&nbsp;<br />- 9 或 109 (*) 默认值 + 毫秒 mon dd yyyy hh:mi:ss:mmmAM（或 PM）&nbsp;<br />10 110 美国 mm-dd-yy&nbsp;<br />11 111 日本 yy/mm/dd&nbsp;<br />12 112 ISO yymmdd&nbsp;<br />- 13 或 113 (*) 欧洲默认值 + 毫秒 dd mon yyyy hh:mm:ss:mmm(24h)&nbsp;<br />14 114 - hh:mi:ss:mmm(24h)&nbsp;<br />- 20 或 120 (*) ODBC 规范 yyyy-mm-dd hh:mm:ss[.fff]&nbsp;<br />- 21 或 121 (*) ODBC 规范（带毫秒） yyyy-mm-dd hh:mm:ss[.fff]&nbsp;<br />- 126(***) ISO8601 yyyy-mm-dd Thh:mm:ss.mmm（不含空格）&nbsp;<br />- 130* Hijri**** dd mon yyyy hh:mi:ss:mmmAM&nbsp;<br />- 131* Hijri**** dd/mm/yy hh:mi:ss:mmmAM<br /><br /><br />* 默认值（style 0 或 100、9 或 109、13 或 113、20 或 120、21 或 121）始终返回世纪数位 (yyyy)。<br />** 当转换为 datetime时输入;当转换为字符数据时输出。<br />*** 专门用于 XML。对于从 datetime或 smalldatetime 到 character 数据的转换，输出格式如表中所示。对于从 float、money 或 smallmoney 到 character 数据的转换，输出等同于 style 2。对于从 real 到 character 数据的转换，输出等同于 style 1。<br />****Hijri 是具有几种变化形式的日历系统，Microsoft&reg; SQL Server&trade; 2000 使用其中的科威特算法。<br />重要 默认情况下，SQL Server 根据截止年份 2049 解释两位数字的年份。即，两位数字的年份 49 被解释为 2049，而两位数字的年份 50 被解释为 1950。许多客户端应用程序（例如那些基于 OLE 自动化对象的客户端应用程序）都使用 2030 作为截止年份。SQL Server 提供一个配置选项（"两位数字的截止年份"），借以更改 SQL Server 所使用的截止年份并对日期进行一致性处理。然而最安全的办法是指定四位数字年份。<br /><br />当从 smalldatetime 转换为字符数据时，包含秒或毫秒的样式将在这些位置上显示零。当从 datetime 或 smalldatetime 值进行转换时，可以通过使用适当的 char 或 varchar 数据类型长度来截断不需要的日期部分。<br /><br /></p>
          <br/>
          <span style="color:red;">
            <a href="http://fastwind.javaeye.com/blog/215729#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 17 Jul 2008 11:53:44 +0800</pubDate>
        <link>http://fastwind.javaeye.com/blog/215729</link>
        <guid>http://fastwind.javaeye.com/blog/215729</guid>
      </item>
      <item>
        <title>SQL Server函数总结</title>
        <author>fastwind</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fastwind.javaeye.com">fastwind</a>&nbsp;
          链接：<a href="http://fastwind.javaeye.com/blog/215726" style="color:red;">http://fastwind.javaeye.com/blog/215726</a>&nbsp;
          发表时间: 2008年07月17日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>一.聚合函数<br />AVG  返回组中值的平均值。空值将被忽略<br />BINARY_CHECKSUM  返回对表中的行或表达式列表计算的二进制校验值。BINARY_CHECKSUM 可用于检测表中行的更改<br />CHECKSUM  返回在表的行上或在表达式列表上计算的校验值。CHECKSUM 用于生成哈希索引<br />CHECKSUM_AGG  返回组中值的校验值。空值将被忽略<br />COUNT  返回组中项目的数量<br />COUNT_BIG  返回组中项目的数量。COUNT_BIG 的使用与 COUNT 函数相似。它们之间的唯一差别是它们的返回值：COUNT_BIG 总是返回 bigint 数据类型值，而 COUNT 则总是返回 int 数据类型值<br />GROUPING  "是一个聚合函数,它产生一个附加的列，当用 CUBE 或 ROLLUP 运算符添加行时，附加的列输出值为1，当所添加的行不是由 CUBE 或 ROLLUP 产生时，附加列值为0。<br />仅在与包含 CUBE 或 ROLLUP 运算符的 GROUP BY 子句相联系的选择列表中才允许分组"<br />MAX  返回表达式的最大值<br />MIN  返回表达式的最小值<br />SUM  返回表达式中所有值的和，或只返回 DISTINCT 值。SUM 只能用于数字列。空值将被忽略<br />STDEV  返回给定表达式中所有值的统计标准偏差<br />STDEVP  返回给定表达式中所有值的填充统计标准偏差<br />VAR  返回给定表达式中所有值的统计方差。<br />VARP  返回给定表达式中所有值的填充的统计方差。<br /><br />二.数学函数<br />ABS  返回给定数字表达式的绝对值<br />ACOS  返回以弧度表示的角度值，该角度值的余弦为给定的 float 表达式；本函数亦称反余弦。<br />ASIN  返回以弧度表示的角度值，该角度值的正弦为给定的 float 表达式；亦称反正弦<br />ATAN  返回以弧度表示的角度值，该角度值的正切为给定的 float 表达式；亦称反正切<br />ATN2  返回以弧度表示的角度值，该角度值的正切介于两个给定的 float 表达式之间；亦称反正切<br />CEILING  返回大于或等于所给数字表达式的最小整数<br />COS  一个数学函数，返回给定表达式中给定角度（以弧度为单位）的三角余弦值<br />COT  一个数学函数，返回给定 float 表达式中指定角度（以弧度为单位）的三角余切值<br />DEGREES  当给出以弧度为单位的角度时，返回相应的以度数为单位的角度<br />EXP  返回所给的 float 表达式的指数值<br />FLOOR  返回小于或等于所给数字表达式的最大整数<br />LOG  返回给定 float 表达式的自然对数<br />LOG10  返回给定 float 表达式的以 10 为底的对数<br />PI  返回 PI 的常量值<br />POWER  返回给定表达式乘指定次方的值<br />RADIANS  对于在数字表达式中输入的度数值返回弧度值<br />RAND  返回 0 到1 之间的随机float 值<br />ROUND  返回数字表达式并四舍五入为指定的长度或精度<br />SIGN  返回给定表达式的正 (+1)、零 (0) 或负 (-1) 号<br />SIN  以近似数字 (float) 表达式返回给定角度（以弧度为单位）的三角正弦值<br />SQUARE  返回给定表达式的平方<br />SQRT  返回给定表达式的平方根<br />TAN  返回输入表达式的正切值<br /><br />三.日期函数<br />DATEADD  在向指定日期加上一段时间的基础上，返回新的 datetime 值。<br />DATEDIFF  返回跨两个指定日期的日期和时间边界数<br />DATENAME  返回代表指定日期的指定日期部分的字符串<br />DATEPART  返回代表指定日期的指定日期部分的整数<br />DAY  返回代表指定日期的天的日期部分的整数<br />GETDATE  按 datetime 值的 Microsoft&reg; SQL Server&trade; 标准内部格式返回当前系统日期和时间<br />GETUTCDATE  返回表示当前 UTC 时间（世界时间坐标或格林尼治标准时间）的 datetime 值<br />MONTH  返回代表指定日期月份的整数<br />YEAR  返回表示指定日期中的年份的整数<br /><br />四.系统函数<br />APP_NAME  返回当前会话的应用程序名称（如果应用程序进行了设置）。<br />CASE 表达式  计算条件列表并返回多个可能结果表达式之一（详见PPT资料）<br />CAST 和 CONVERT  将某种数据类型的表达式显式转换为另一种数据类型（详见PPT资料）<br />COALESCE  返回其参数中第一个非空表达式<br />COLLATIONPROPERTY  返回给定排序规则的属性<br />CURRENT_TIMESTAMP  返回当前的日期和时间。此函数等价于 GETDATE()<br />CURRENT_USER  返回当前的用户。此函数等价于 USER_NAME()<br />DATALENGTH  返回任何表达式所占用的字节数<br />@@ERROR  返回最后执行的 Transact-SQL 语句的错误代码<br />fn_helpcollations  返回 Microsoft&reg; SQL Server&trade; 2000 支持的所有排序规则的列表。<br />fn_servershareddrives  返回由群集服务器使用的共享驱动器名称<br />fn_virtualfilestats  返回对数据库文件（包括日志文件）的 I/O 统计<br />FORMATMESSAGE  从 sysmessages 现有的消息构造消息。FORMATMESSAGE 与 RAISERROR 语句的功能相似；但 RAISERROR 立即输出消息而 FORMATMESSAGE 返回编辑后的信息供进一步处理<br />GETANSINULL  返回会话的数据库的默认为空性。<br />HOST_ID  返回工作站标识号。<br />HOST_NAME  返回工作站名称。<br />IDENT_CURRENT  返回为任何会话和任何作用域中的指定表最后生成的标识值。&nbsp;<br />IDENT_INCR  返回增量值（返回形式为 numeric(@@MAXPRECISION,0)），该值是在带有标识列的表或视图中创建标识列时指定的<br />IDENT_SEED  返回种子值（返回形式为 numeric(@@MAXPRECISION,0)），该值是在带有标识列的表或视图中创建标识列时指定的<br />@@IDENTITY  返回最后插入的标识值<br />IDENTITY（函数）  只用在带有 INTO table 子句的 SELECT 语句中，以将标识列插入到新表中。尽管类似，但是 IDENTITY 函数不是与 CREATE TABLE 和 ALTER TABLE 一起使用的 IDENTITY 属性。（自动采番时可以起到作用）<br />ISDATE  确定输入表达式是否为有效的日期<br />ISNULL  使用指定的替换值替换 NULL<br />ISNUMERIC  确定表达式是否为一个有效的数字类型<br />NEWID  创建 uniqueidentifier 类型的唯一值<br />NULLIF  如果两个指定的表达式相等，则返回空值。<br />PARSENAME  返回对象名的指定部分。可以检索的对象部分有对象名、所有者名称、数据库名称和服务器名称<br />PERMISSIONS  返回一个包含位图的值，表明当前用户的语句、对象或列权限。<br />@@ROWCOUNT  返回受上一语句影响的行数<br />ROWCOUNT_BIG  返回受执行的最后一个语句影响的行数。该函数的功能与 @@ROWCOUNT 一样，除非 ROWCOUNT_BIG 的返回类型是 bigint。<br />SCOPE_IDENTITY  返回插入到同一作用域中的 IDENTITY 列内的最后一个 IDENTITY 值。<br />SERVERPROPERTY  返回有关服务器实例的属性信息<br />SESSIONPROPERTY  返回会话的 SET 选项设置<br />SESSION_USER  是一个 niladic 函数，允许在未指定默认值时将系统为当前会话的用户名提供的值插入到表中。还允许在查询、错误信息等中使用用户名<br />STATS_DATE  返回最后一次更新指定索引统计的日期<br />SYSTEM_USER  返回当前系统用户名<br />@@TRANCOUNT  返回当前连接的活动事务数<br />USER_NAME  返回给定标识号的用户数据库用户名<br /><br />五.字符函数<br />ASCII  返回字符表达式最左端字符的ASCII代码值。<br />CHAR  将intASCII代码转换为字符的字符串函数。<br />CHARINDEX  返回字符串中指定表达式的起始位置<br />DIFFERENCE  以整数返回两个字符表达式的SOUNDEX值之差。<br />LEFT  返回字符串中从左边开始指定个数的字符。<br />LEN  返回给定字符串表达式的字符（而不是字节）个数，其中不包含尾随空格<br />LOWER  将大写字符数据转换为小写字符数据后返回字符表达式。<br />LTRIM  删除起始空格后返回字符表达式<br />NCHAR  根据Unicode标准所进行的定义，用给定整数代码返回Unicode字符<br />PATINDEX  返回指定表达式中某模式第一次出现的起始位置；如果在全部有效的文本和字符数据类型中没有找到该模式，则返回零<br />REPLACE  用第三个表达式替换第一个字符串表达式中出现的所有第二个给定字符串表达式<br />QUOTENAME  返回带有分隔符的Unicode字符串，分隔符的加入可使输入的字符串成为有效的Microsoft&reg;SQLServer&trade;分隔标识符。<br />REPLICATE  以指定的次数重复字符表达式<br />REVERSE  返回字符表达式的反转。<br />RIGHT  返回字符串中从右边开始指定个数的字符<br />RTRIM  截断所有尾随空格后返回一个字符串<br />SOUNDEX  返回由四个字符组成的代码(SOUNDEX)以评估两个字符串的相似性<br />SPACE  返回由重复的空格组成的字符串<br />STR  由数字数据转换来的字符数据<br />STUFF  删除指定长度的字符并在指定的起始点插入另一组字符<br />SUBSTRING  返回字符、binary、text或image表达式的一部分<br />UNICODE  按照Unicode标准的定义，返回输入表达式的第一个字符的整数值<br />UPPER  返回将小写字符数据转换为大写的字符表达式<br /></p>
          <br/>
          <span style="color:red;">
            <a href="http://fastwind.javaeye.com/blog/215726#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 17 Jul 2008 11:46:13 +0800</pubDate>
        <link>http://fastwind.javaeye.com/blog/215726</link>
        <guid>http://fastwind.javaeye.com/blog/215726</guid>
      </item>
      <item>
        <title>SQL查询语句精华使用简要</title>
        <author>fastwind</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fastwind.javaeye.com">fastwind</a>&nbsp;
          链接：<a href="http://fastwind.javaeye.com/blog/215486" style="color:red;">http://fastwind.javaeye.com/blog/215486</a>&nbsp;
          发表时间: 2008年07月16日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>一、 简单查询&nbsp;<br /><br />　　简单的Transact-SQL查询只包括选择列表、FROM子句和WHERE子句。它们分别说明所查询列、查询的表或视图、以及搜索条件等。<br />　　例如，下面的语句查询testtable表中姓名为&ldquo;张三&rdquo;的nickname字段和email字段。<br /><br /><br />&nbsp;　 &nbsp;SELECT nickname,email<br />　　FROM testtable<br />　　WHERE name='张三'&nbsp;<br /><br /><br />　　(一) 选择列表<br /><br />　　选择列表(select_list)指出所查询列，它可以是一组列名列表、星号、表达式、变量(包括局部变量和全局变量)等构成。<br /><br />　　1、选择所有列<br /><br />　　例如，下面语句显示testtable表中所有列的数据：<br /><br /><br /><br />&nbsp;　　SELECT *<br />　　FROM testtable&nbsp;<br /><br /><br /><br />　　2、选择部分列并指定它们的显示次序<br /><br />　　查询结果集合中数据的排列顺序与选择列表中所指定的列名排列顺序相同。<br />　　例如：<br /><br /><br /><br />&nbsp;　　SELECT nickname,email<br />　　FROM testtable&nbsp;<br /><br /><br /><br />　　3、更改列标题<br /><br />　　在选择列表中，可重新指定列标题。定义格式为：<br />　　列标题=列名<br />　　列名 列标题<br />　　如果指定的列标题不是标准的标识符格式时，应使用引号定界符，例如，下列语句使用汉字显示列标题：<br /><br /><br /><br />&nbsp;　　SELECT 昵称=nickname,电子邮件=email<br />　　FROM testtable&nbsp;<br /><br /><br /><br /><br />　　4、删除重复行<br /><br />　　SELECT语句中使用ALL或DISTINCT选项来显示表中符合条件的所有行或删除其中重复的数据行，默认为ALL。使用DISTINCT选项时，对于所有重复的数据行在SELECT返回的结果集合中只保留一行。<br /><br />　　5、限制返回的行数<br /><br />　　使用TOP n [PERCENT]选项限制返回的数据行数，TOP n说明返回n行，而TOP n PERCENT时，说明n是表示一百分数，指定返回的行数等于总行数的百分之几。<br />　　例如：<br /><br /><br /><br />&nbsp;　　SELECT TOP 2 *<br />　　FROM testtable<br />　　SELECT TOP 20 PERCENT *<br />　　FROM testtable&nbsp;<br /><br /><br /><br /><br />　　(二)FROM子句&nbsp;<br /><br />　　FROM子句指定SELECT语句查询及与查询相关的表或视图。在FROM子句中最多可指定256个表或视图，它们之间用逗号分隔。<br />　　在FROM子句同时指定多个表或视图时，如果选择列表中存在同名列，这时应使用对象名限定这些列所属的表或视图。例如在usertable和citytable表中同时存在cityid列，在查询两个表中的cityid时应使用下面语句格式加以限定：<br /><br /><br /><br /><br />&nbsp;　　SELECT username,citytable.cityid<br />　　FROM usertable,citytable<br />　　WHERE usertable.cityid=citytable.cityid&nbsp;<br /><br /><br /><br />　　在FROM子句中可用以下两种格式为表或视图指定别名：<br />　　表名 as 别名<br />　　表名 别名<br />&nbsp; &nbsp; &nbsp; 例如上面语句可用表的别名格式表示为：<br /><br />&nbsp;　　SELECT username,b.cityid<br />　　FROM usertable a,citytable b<br />　　WHERE a.cityid=b.cityid&nbsp;<br /><br />　　SELECT不仅能从表或视图中检索数据，它还能够从其它查询语句所返回的结果集合中查询数据。<br /><br />　　例如：<br /><br />&nbsp;　　SELECT a.au_fname+a.au_lname<br />　　FROM authors a,titleauthor ta<br />　　(SELECT title_id,title<br />　　FROM titles<br />　　WHERE ytd_sales&gt;10000<br />　　) AS t<br />　　WHERE a.au_id=ta.au_id<br />　　AND ta.title_id=t.title_id&nbsp;<br /><br />　　此例中，将SELECT返回的结果集合给予一别名t，然后再从中检索数据。<br /><br />　　(三) 使用WHERE子句设置查询条件<br /><br />　　WHERE子句设置查询条件，过滤掉不需要的数据行。例如下面语句查询年龄大于20的数据：<br /><br />&nbsp;　　SELECT *<br />　　FROM usertable<br />　　WHERE age&gt;20&nbsp;<br /><br />　　WHERE子句可包括各种条件运算符：<br />　　比较运算符(大小比较)：&gt;、&gt;=、=、&lt;、&lt;=、&lt;&gt;、!&gt;、!&lt;<br />　　范围运算符(表达式值是否在指定的范围)：BETWEEN&hellip;AND&hellip;<br />　　NOT BETWEEN&hellip;AND&hellip;<br />　　列表运算符(判断表达式是否为列表中的指定项)：IN (项1,项2&hellip;&hellip;)<br />　　NOT IN (项1,项2&hellip;&hellip;)<br />　　模式匹配符(判断值是否与指定的字符通配格式相符):LIKE、NOT LIKE<br />　　空值判断符(判断表达式是否为空)：IS NULL、NOT IS NULL<br />　　逻辑运算符(用于多条件的逻辑连接)：NOT、AND、OR<br /><br />　　1、范围运算符例：age BETWEEN 10 AND 30相当于age&gt;=10 AND age&lt;=30<br />　　2、列表运算符例：country IN ('Germany','China')<br />　　3、模式匹配符例：常用于模糊查找，它判断列值是否与指定的字符串格式相匹配。可用于char、varchar、text、ntext、datetime和smalldatetime等类型查询。<br />　　可使用以下通配字符：<br />　　百分号%：可匹配任意类型和长度的字符，如果是中文，请使用两个百分号即%%。<br />　　下划线_：匹配单个任意字符，它常用来限制表达式的字符长度。<br />　　方括号[]：指定一个字符、字符串或范围，要求所匹配对象为它们中的任一个。[^]：其取值也[] 相同，但它要求所匹配对象为指定字符以外的任一个字符。<br />　　例如：<br />　　限制以Publishing结尾，使用LIKE '%Publishing'<br />　　限制以A开头：LIKE '[A]%'<br />　　限制以A开头外：LIKE '[^A]%'<br /><br />&nbsp; &nbsp; &nbsp; 4、空值判断符例WHERE age IS NULL<br /><br />　　5、逻辑运算符：优先级为NOT、AND、OR<br /><br />　　(四)查询结果排序&nbsp;<br /><br />　　使用ORDER BY子句对查询返回的结果按一列或多列排序。ORDER BY子句的语法格式为：<br />　　ORDER BY {column_name [ASC|DESC]} [,&hellip;n]<br />　　其中ASC表示升序，为默认值，DESC为降序。ORDER BY不能按ntext、text和image数据类型进行排<br />　　序。<br />　　例如：<br /><br />&nbsp;　　SELECT *<br />　　FROM usertable<br />　　ORDER BY age desc,userid ASC&nbsp;<br /><br />　　另外，可以根据表达式进行排序。<br /><br />　　二、 联合查询<br /><br />　　UNION运算符可以将两个或两个以上上SELECT语句的查询结果集合合并成一个结果集合显示，即执行联合查询。UNION的语法格式为：<br /><br />&nbsp;　　select_statement<br />　　UNION [ALL] selectstatement<br />　　[UNION [ALL] selectstatement][&hellip;n]&nbsp;<br /><br />　　其中selectstatement为待联合的SELECT查询语句。<br /><br />　　ALL选项表示将所有行合并到结果集合中。不指定该项时，被联合查询结果集合中的重复行将只保留一行。<br /><br />　　联合查询时，查询结果的列标题为第一个查询语句的列标题。因此，要定义列标题必须在第一个查询语句中定义。要对联合查询结果排序时，也必须使用第一查询语句中的列名、列标题或者列序号。<br /><br />　　在使用UNION 运算符时，应保证每个联合查询语句的选择列表中有相同数量的表达式，并且每个查询选择表达式应具有相同的数据类型，或是可以自动将它们转换为相同的数据类型。在自动转换时，对于数值类型，系统将低精度的数据类型转换为高精度的数据类型。<br /><br />　　在包括多个查询的UNION语句中，其执行顺序是自左至右，使用括号可以改变这一执行顺序。例如：<br /><br />　　查询1 UNION (查询2 UNION 查询3)<br /><br />　　三、连接查询<br /><br />　　通过连接运算符可以实现多个表查询。连接是关系数据库模型的主要特点，也是它区别于其它类型数据库管理系统的一个标志。<br /><br />　　在关系数据库管理系统中，表建立时各数据之间的关系不必确定，常把一个实体的所有信息存放在一个表中。当检索数据时，通过连接操作查询出存放在多个表中的不同实体的信息。连接操作给用户带来很大的灵活性，他们可以在任何时候增加新的数据类型。为不同实体创建新的表，尔后通过连接进行查询。<br /><br />　　连接可以在SELECT 语句的FROM子句或WHERE子句中建立，似是而非在FROM子句中指出连接时有助于将连接操作与WHERE子句中的搜索条件区分开来。所以，在Transact-SQL中推荐使用这种方法。<br /><br />　　SQL-92标准所定义的FROM子句的连接语法格式为：<br /><br />&nbsp;　　FROM join_table join_type join_table<br />　　[ON (join_condition)]&nbsp;<br /><br />　　其中join_table指出参与连接操作的表名，连接可以对同一个表操作，也可以对多表操作，对同一个表操作的连接又称做自连接。<br /><br />&nbsp; &nbsp; &nbsp; join_type 指出连接类型，可分为三种：内连接、外连接和交叉连接。内连接(INNER JOIN)使用比较运算符进行表间某(些)列数据的比较操作，并列出这些表中与连接条件相匹配的数据行。根据所使用的比较方式不同，内连接又分为等值连接、自然连接和不等连接三种。外连接分为左外连接(LEFT OUTER JOIN或LEFT JOIN)、右外连接(RIGHT OUTER JOIN或RIGHT JOIN)和全外连接(FULL OUTER JOIN或FULL JOIN)三种。与内连接不同的是，外连接不只列出与连接条件相匹配的行，而是列出左表(左外连接时)、右表(右外连接时)或两个表(全外连接时)中所有符合搜索条件的数据行。<br /><br />　　交叉连接(CROSS JOIN)没有WHERE 子句，它返回连接表中所有数据行的笛卡尔积，其结果集合中的数据行数等于第一个表中符合查询条件的数据行数乘以第二个表中符合查询条件的数据行数。<br /><br />　　连接操作中的ON (join_condition) 子句指出连接条件，它由被连接表中的列和比较运算符、逻辑运算符等构成。<br /><br />　　无论哪种连接都不能对text、ntext和image数据类型列进行直接连接，但可以对这三种列进行间接连接。例如：<br /><br />&nbsp;　　SELECT p1.pub_id,p2.pub_id,p1.pr_info<br />　　FROM pub_info AS p1 INNER JOIN pub_info AS p2<br />　　ON DATALENGTH(p1.pr_info)=DATALENGTH(p2.pr_info)&nbsp;<br /><br />　　(一)内连接<br />　　内连接查询操作列出与连接条件匹配的数据行，它使用比较运算符比较被连接列的列值。内连接分三种：<br />　　1、等值连接：在连接条件中使用等于号(=)运算符比较被连接列的列值，其查询结果中列出被连接表中的所有列，包括其中的重复列。<br />　　2、不等连接： 在连接条件使用除等于运算符以外的其它比较运算符比较被连接的列的列值。这些运算符包括&gt;、&gt;=、&lt;=、&lt;、!&gt;、!&lt;和&lt;&gt;。<br />　　3、自然连接：在连接条件中使用等于(=)运算符比较被连接列的列值，但它使用选择列表指出查询结果集合中所包括的列，并删除连接表中的重复列。<br />　　例，下面使用等值连接列出authors和publishers表中位于同一城市的作者和出版社：<br /><br />&nbsp;　　SELECT *<br />　　FROM authors AS a INNER JOIN publishers AS p<br />　　ON a.city=p.city<br />　　又如使用自然连接，在选择列表中删除authors 和publishers 表中重复列(city和state)：<br />　　SELECT a.*,p.pub_id,p.pub_name,p.country<br />　　FROM authors AS a INNER JOIN publishers AS p<br />　　ON a.city=p.city&nbsp;<br /><br />　　(二)外连接<br />　　内连接时，返回查询结果集合中的仅是符合查询条件( WHERE 搜索条件或 HAVING 条件)和连接条件的行。而采用外连接时，它返回到查询结果集合中的不仅包含符合连接条件的行，而且还包括左表(左外连接时)、右表(右外连接时)或两个边接表(全外连接)中的所有数据行。如下面使用左外连接将论坛内容和作者信息连接起来：<br /><br />&nbsp;　　SELECT a.*,b.* FROM luntan LEFT JOIN usertable as b<br />　　ON a.username=b.username&nbsp;<br /><br />　　下面使用全外连接将city表中的所有作者以及user表中的所有作者，以及他们所在的城市：<br /><br />&nbsp;　　SELECT a.*,b.*<br />　　FROM city as a FULL OUTER JOIN user as b<br />　　ON a.username=b.username&nbsp;<br /><br /><br />　　(三)交叉连接<br />　　交叉连接不带WHERE 子句，它返回被连接的两个表所有数据行的笛卡尔积，返回到结果集合中的数据行数等于第一个表中符合查询条件的数据行数乘以第二个表中符合查询条件的数据行数。例，titles表中有6类图书，而publishers表中有8家出版社，则下列交叉连接检索到的记录数将等<br /><br />&nbsp;　　于6*8=48行。<br />　　SELECT type,pub_name<br />　　FROM titles CROSS JOIN publishers<br />　　ORDER BY type<br />　　[Post=0][/Post]&nbsp;<br /><br /><br /><br /></p>
          <br/>
          <span style="color:red;">
            <a href="http://fastwind.javaeye.com/blog/215486#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 16 Jul 2008 17:13:37 +0800</pubDate>
        <link>http://fastwind.javaeye.com/blog/215486</link>
        <guid>http://fastwind.javaeye.com/blog/215486</guid>
      </item>
      <item>
        <title>java中的URLEncoder和URLDecoder类</title>
        <author>fastwind</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fastwind.javaeye.com">fastwind</a>&nbsp;
          链接：<a href="http://fastwind.javaeye.com/blog/213732" style="color:red;">http://fastwind.javaeye.com/blog/213732</a>&nbsp;
          发表时间: 2008年07月11日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>/*&nbsp;<br /><br />&nbsp;    网页中的表单使用POST方法提交时，数据内容的类型是 application/x-www-form-urlencoded，这种类型会：&nbsp;<br />1.字符"a"-"z"，"A"-"Z"，"0"-"9"，"."，"-"，"*"，和"_" 都不会被编码;<br />2.将空格转换为加号 (+) ;<br />3.将非文本内容转换成"%xy"的形式,xy是两位16进制的数值;<br />4.在每个 name=value 对之间放置 &amp; 符号。<br />*/<br /><br />&nbsp;   URLEncoder类包含将字符串转换为application/x-www-form-urlencoded MIME 格式的静态方法。<br /><br />&nbsp;       web设计者面临的众多难题之一便是怎样处理不同操作系统间的差异性。这些差异性能引起URL方面的问题：例如，一些操作系统允许文件名中含有空格符，有些又不允许。大多数操作系统不会认为文件名中含有符号&ldquo;#&rdquo;会有什么特殊含义；但是在一个URL中，符号&ldquo;#&rdquo;表示该文件名已经结束，后面会紧跟一个fragment（部分）标识符。其他的特殊字符，非字母数字字符集，它们在URL或另一个操作系统上都有其特殊的含义，表述着相似的问题。为了解决这些问题，我们在URL中使用的字符就必须是一个ASCII字符集的固定字集中的元素，具体如下：<br /><br />1.大写字母A-Z<br />2.小写字母a-z<br />3.数字 0-9<br />4.标点符 - _ . ! ~ * ' (和 ,)<br /><br />&nbsp;      诸如字符: / &amp; ? @ # ; $ + = 和 %也可以被使用，但是它们各有其特殊的用途，如果一个文件名包括了这些字符（ / &amp; ? @ # ; $ + = %），这些字符和所有其他字符就应该被编码。<br /><br />&nbsp;      编码过程非常简单，任何字符只要不是ASCII码数字，字母，或者前面提到的标点符，它们都将被转换成字节形式，每个字节都写成这种形式：一个&ldquo;%&rdquo;后面跟着两位16进制的数值。空格是一个特殊情况，因为它们太平常了。它除了被编码成&ldquo;%20&rdquo;以外，还能编码为一个&ldquo;+&rdquo;。加号（+）本身被编码为%2B。当/ # = &amp; 和?作为名字的一部分来使用时，而不是作为URL部分之间的分隔符来使用时，它们都应该被编码。<br /><br />&nbsp;     WARNING这种策略在存在大量字符集的异构环境中效果不甚理想。例如：在U.S. Windows 系统中, &eacute; 被编码为 %E9. 在 U.S. Mac中被编码为%8E。这种不确定性的存在是现存的URI的一个明显的不足。所以在将来URI的规范当中应该通过国际资源标识符(IRIs)进行改善。<br /><br /><br />&nbsp;&nbsp;<br /><br />&nbsp;    类URL并不自动执行编码或解码工作。你能生成一个URL对象，它可以包括非法的ASCII和非ASCII字符和/或%xx。当用方法getPath() 和toExternalForm( ) 作为输出方法时，这种字符和转移符不会自动编码或解码。你应对被用来生成一个URL对象的字符串对象负责，确保所有字符都会被恰当地编码。<br /><br /><br />&nbsp;    幸运的是，java提供了一个类URLEncoder把string编码成这种形式。Java1.2增加了一个类URLDecoder它能以这种形式解码string。这两个类都不用初始化：<br />public class URLDecoder extends Object<br />public class URLEncoder extends Object<br /><br />一、URLEncoder<br /><br />&nbsp;    在java1.3和早期版本中，类java.net.URLEncoder包括一个简单的静态方法encode( )， 它对string以如下规则进行编码：<br />&nbsp;      public static String encode(String s)<br /><br />&nbsp;    这个方法总是用它所在平台的默认编码形式，所以在不同系统上，它就会产生不同的结果。结果java1.4中，这个方法被另一种方法取代了。该方法要求你自己指定编码形式：<br /><br />public static String encode(String s, String encoding) throws UnsupportedEncodingException<br /><br />&nbsp;     两种关于编码的方法，都把任何非字母数字字符转换成%xx（除了空格，下划线(_)，连字符（?）,句号（。）,和星号（*））。两者也都编码所以的非ASCII字符。空格被转换成一个加号。这些方法有一点过分累赘了；它们也把&ldquo;~&rdquo;，&ldquo;&lsquo;&rdquo;，&ldquo;（）&rdquo;转换成%xx，即使它们完全用不着这样做。尽管这样，但是这种转换并没被URL规范所禁止。所以web浏览器会自然地处理这些被过分编码后的URL。<br /><br />&nbsp;     两中关于编码的方法都返回一个新的被编码后的string，java1.3的方法encode( ) 使用了平台的默认编码形式，得到%xx。这些编码形式典型的有：在 U.S. Unix 系统上的ISO-8859-1, 在U.S. Windows 系统上的Cp1252,在U.S. Macs上的MacRoman，和其他本地字符集等。因为编码解码过程都是与本地操作平台相关的，所以这些方法是令人不爽的，不能跨平台的。<br />&nbsp;     这就明确地回答了为什么在java1.4中这种方法被抛弃了，转而投向了要求以自己指定编码形式的这种方法。尽管如此，如果你执意要使用所在平台的默认编码形式，你的程序将会像在java1.3中的程序一样，是本地平台相关的。在另一种编码的方法中，你应该总是用UTF-8，而不是其他什么。UTF-8比起你选的其他的编码形式来说，它能与新的web浏览器和更多的其他软件相兼容。<br /><br />&nbsp;     例子7-8是使用URLEncoder.encode( ) 来打印输出各种被编码后的string。它需要在java1.4或更新的版本中编译和运行。<br /><br />Example 7-8. x-www-form-urlencoded strings&nbsp;<br /><br /><br />下面就是它的输出。需要注意的是这些代码应该以其他编码形式被保存而不是以ASCII码的形式，还有就是你选择的编码形式应该作为一个参数传给编译器，让编译器能据此对源代码中的非ASCII字符作出正确的解释。<br /><br />% javac -encoding UTF8 EncoderTest %&nbsp;<br /><br />java EncoderTest<br />This+string+has+spaces<br />This*string*has*asterisks<br />This%25string%25has%25percent%25signs<br />This%2Bstring%2Bhas%2Bpluses<br />This%2Fstring%2Fhas%2Fslashes<br />This%22string%22has%22quote%22marks<br />This%3Astring%3Ahas%3Acolons<br />This%7Estring%7Ehas%7Etildes<br />This%28string%29has%28parentheses%29<br />This.string.has.periods<br />This%3Dstring%3Dhas%3Dequals%3Dsigns<br />This%26string%26has%26ampersands<br />This%C3%A9string%C3%A9has%C3%A9non-ASCII+characters<br /><br />特别需要注意的是这个方法编码了符号，&ldquo;\&rdquo; ,&amp;,=,和：。它不会尝试着去规定在一个URL中这些字符怎样被使用。由此，所以你不得不分块编码你的URL,而不是把整个URL一次传给这个方法。这是很重要的，因为对类URLEncoder最通常的用法就是查询string，为了和服务器端使用GET方法的程序进行交互。例如，假设你想编码这个查询sting，它用来搜索AltaVista网站：<br />pg=q&amp;kl=XX&amp;stype=stext&amp;q=+"Java+I/O"&amp;search.x=38&amp;search.y=3<br /><br />这段代码对其进行编码：<br />String query = URLEncoder.encode( "pg=q&amp;kl=XX&amp;stype=stext&amp;q=+\"Java+I/O\"&amp;search.x=38&amp;search.y=3");System.out.println(query);<br /><br />不幸的是，得到的输出是:<br />pg%3Dq%26kl%3DXX%26stype%3Dstext%26q%3D%2B%22Java%2BI%2FO%22%26search.x%3D38%26search.y%3D3<br /><br />出现这个问题就是方法URLEncoder.encode( ) 在进行盲目地编码。它不能区分在URL或者查询string中被用到的特殊字符（象前面string中的&ldquo;＝&rdquo;，和&ldquo;&amp;&rdquo;）和确实需要被编码的字符。由此，所以URL需要像下面这样一次只编码一块：<br /><br />String query = URLEncoder.encode("pg");<br />query += "=";<br />query += URLEncoder.encode("q");<br />query += "&amp;";<br />query += URLEncoder.encode("kl");<br />query += "=";<br />query += URLEncoder.encode("XX");<br />query += "&amp;";<br />query += URLEncoder.encode("stype");<br />query += "=";<br />query += URLEncoder.encode("stext");<br />query += "&amp;";<br />query += URLEncoder.encode("q");<br />query += "=";<br />query += URLEncoder.encode("\"Java I/O\"");<br />query += "&amp;";<br />query += URLEncoder.encode("search.x");<br />query += "=";<br />query += URLEncoder.encode("38");<br />query += "&amp;";<br />query += URLEncoder.encode("search.y");<br />query += "=";<br />query += URLEncoder.encode("3");<br />System.out.println(query);<br /><br />这才是你真正想得到的输出：<br />pg=q&amp;kl=XX&amp;stype=stext&amp;q=%2B%22Java+I%2FO%22&amp;search.x=38&amp;search.y=3<br /><br />例子7-9是一个QueryString类。在一个java对象中，它使用了类URLEncoder来编码连续的属性名和属性值对，这个java对象被用来发送数据到服务器端的程序。<br /><br />当你在创建一个QueryString对象时，你可以把查询string中的第一个属性对传递给类QueryString的构造函数，得到初始string。如果要继续加入后面的属性对，就应调用方法add（），它也能接受两个string作为参数，能对它们进行编码。方法getQuery( )返回一个属性对被逐个编码后得到的整个string。<br /><br />The QueryString class<br /><br />
<pre name="code" class="java">import java.net.URLEncoder;
import java.io.UnsupportedEncodingException;

public class QueryString {
  private StringBuffer query = new StringBuffer();

public QueryString(String name, String value) { 
  encode(name, value);
}

public synchronized void add(String name, String value) {
  query.append('&amp;');
  encode(name, value);
}

private synchronized void encode(String name, String value) {
  try {
  query.append(URLEncoder.encode(name, "UTF-8"));
  query.append('=');
  query.append(URLEncoder.encode(value, "UTF-8"));
} catch (UnsupportedEncodingException ex) {
  throw new RuntimeException("Broken VM does not support UTF-8");
}
}

public String getQuery() {
  return query.toString();
}

public String toString() {
  return getQuery();
}
}</pre>
&nbsp;<br /><br />利用这个类，现在我们就能对前面那个例子中的string进行编码了:<br />QueryString qs = new QueryString("pg", "q");<br />qs.add("kl", "XX");<br />qs.add("stype", "stext");<br />qs.add("q", "+\"Java I/O\"");<br />qs.add("search.x", "38");<br />qs.add("search.y", "3");<br />String url = "http://www.altavista.com/cgi-bin/query?" + qs;<br />System.out.println(url);<br /><br />二、URLDecoder<br />&nbsp;    与URLEncoder 类相对应的URLDecoder 类有两种静态方法。它们解码以x-www-form-url-encoded这种形式编码的string。也就是说，它们把所有的加号（+）转换成空格符，把所有的%xx分别转换成与之相对应的字符：<br />public static String decode(String s) throws Exception<br />public static String decode(String s, String encoding) // Java 1.4 throws UnsupportedEncodingException<br /><br />第一种解码方法在java1.3和java1.2中使用。第二种解码方法在java1.4和更新的版本中使用。如果你拿不定主意用哪种编码方式，那就选择UTF-8吧。它比其他任何的编码形式更有可能得到正确的结果。<br /><br />如果string包含了一个&ldquo;%&rdquo;，但紧跟其后的不是两位16进制的数或者被解码成非法序列，该方法就会抛出IllegalArgumentException 异常。当下次再出现这种情况时，它可能就不会被抛出了。这是与运行环境相关的，当检查到有非法序列时，抛不抛出IllegalArgumentException 异常，这时到底会发生什么是不确定的。在Sun's JDK 1.4中，不会抛出什么异常，它会把一些莫名其妙的字节加进不能被顺利编码的string中。这的确令人头疼，可能就是一个安全漏洞。<br /><br />由于这个方法没有触及到非转义字符，所以你可以把整个URL作为参数传给该方法，不用像之前那样分块进行。例如：<br />String input = "http://www.altavista.com/cgi-bin/" + "query?pg=q&amp;kl=XX&amp;stype=stext&amp;q=%2B%22Java+I%2FO%22&amp;search.x=38&amp;search.y=3";&nbsp;<br />try {&nbsp;<br />&nbsp;  String output = URLDecoder.decode(input, "UTF-8");&nbsp;<br />&nbsp;  System.out.println(output);&nbsp;<br />}<br /><br /><br />
<pre name="code" class="java">import java.net.URLEncoder;
import java.net.URLDecoder;
import java.io.UnsupportedEncodingException;
public class EncoderTest {
  public static void main(String[] args) {
  try {
  System.out.println(URLEncoder.encode("This string has spaces","UTF-8"));
  System.out.println(URLEncoder.encode("This*string*has*asterisks","UTF-8"));
  System.out.println(URLEncoder.encode("This%string%has%percent%signs", "UTF-8"));
  System.out.println(URLEncoder.encode("This+string+has+pluses","UTF-8"));
  System.out.println(URLEncoder.encode("This/string/has/slashes","UTF-8"));
  System.out.println(URLEncoder.encode("This\"string\"has\"quote\"marks", "UTF-8"));
  System.out.println(URLEncoder.encode("This:string:has:colons","UTF-8"));
  System.out.println(URLEncoder.encode("This~string~has~tildes","UTF-8"));
  System.out.println(URLEncoder.encode("This(string)has(parentheses)", "UTF-8"));
  System.out.println(URLEncoder.encode("This.string.has.periods","UTF-8"));
  System.out.pri