<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>一只在森林中寻找树洞的公猴</title>
    <description></description>
    <link>http://fx19800215.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> 关于中小型项目团队建设的若干思考（1）     </title>
        <author>fx19800215</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fx19800215.javaeye.com">fx19800215</a>&nbsp;
                    链接：<a href="http://fx19800215.javaeye.com/blog/154597" style="color:red;">http://fx19800215.javaeye.com/blog/154597</a>&nbsp;
          发表时间: 2008年01月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          &nbsp;兵书有云：&ldquo;兵不在多，而在于精；将不再广，而在于勇&rdquo;。因此一个软件项目能否成功其关键并不在于有多少人，而在于如何建设一个高效、和谐、反应快速的团队。但是说起来简单，可在实际工作中我们总会遇到许多难以预料的问题，这些问题有些是技术上面的有些并不是技术上面的，有些问题可能在目前中国式的软件开发中永远也不能很好的解决。但是，生活还要继续，程序员也需要面包和牛奶，面对这样的情况我们所要做的是&ldquo;把问题搞定！&rdquo;。 <p>&nbsp;&nbsp;&nbsp; 目前根据开发团队的人数基本上可以把软件开发团队分为：<br />&nbsp;&nbsp;&nbsp; 1、大型团队：我个人认为大型的团队没有一个固定概率，通常有若干个中型或者微型的团队中一起来完成一件事情，这样的团队 可以称之为大型团队。诸如微软、google这样的团队不在本文到讨论范围之内。<br />&nbsp;&nbsp;&nbsp; 2、中型团队：通常团队的人数字20人以下，10人以上并且在做通一件事情的开发团队。这样的开发团队可以有这样几个部分组成。<br />&nbsp;&nbsp;&nbsp; 3、小型团队：5人以上，10人以下。<br />&nbsp;&nbsp;&nbsp; 4、微型团队：5人以下，有时候甚至一个人，笔者就有过这样的经历。<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在web2.0时代造就了大量新兴的网站，这些网站在开始的时候通常是由一些小型团队开始的，如果这个时候没有组建一个好的团队那么项目可能坚持不到凤凰涅磐的那天（通常是被收购或者得到GC :)）。同时web2.0时代一切都趋于理性，各路财神无不看紧钱袋因此创业型的团队不可能在一开始就组件很大的团队，因此中小团队的建设显得尤为重要。&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 凡是项目团队肯定就要有一个负责人，这个负责人就是通常所说的项目经理。可能大家所经历的团队多是一个或者几个大虾带着一群小虾一起开发。现在第一个问题来了，项目经理到底要不要有很好的技术底蕴？我想大家在面试的时候经常会被问到这样一个问题：&ldquo;如果某完全不懂技术的人领导你，你会服从他的领导吗&rdquo;，我想大多数人都会回答：&rdquo;服从&ldquo;，虽然心里并不是真服从。但我们经常遇到的一个情况是：项目经理对下面的开发人员失去了控制。所以目前大多数项目经理都是在程序员中产生的，我想这也是大多数程序员奋斗的目标吧（之所以说是大多数那是因为我们不得不承认有些人天生确实不适合管理一个团队）。可是许多技术高手走上管理岗位后变得无所适从，甚至有的既没有有效的带领团队很好的工作，同时也荒废了自己的&rdquo;武艺&ldquo;。那到底项目经理应该由什么样的人来担任呢。依笔者愚见，在中国式的软件开发中项目经理是那些有管理才能的技术高手来担任。至于其原因笔者认为有以下几点：</p><p><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、和开发人员的交流问题<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 项目经理如果不是搞技术出身的话那么他很难理解开发人员的一些行为，同时他也不能程序可以理解的语言将问题描述清楚。还有，&nbsp;&nbsp;没有搞过技术开发的项目经理通常不能很好的理解程序员的工作习惯。笔者就遇到过这样的一件事情，开发人员正在为赶进度全力以&nbsp;&nbsp;赴对某个技术难题进行攻关，这个时候项目经理在写一份需求，他有个并不是很重要的问题需要咨询开发人员，于是这位老兄随即打&nbsp;&nbsp;断开发人员的思路，向他询问这个问题。结果是可想而知的，开发人员最反感在他集中精力解决某个问题的时候被人打断。其实搞过&nbsp;&nbsp;技术攻关的人都知道，如果换个时候提问结果是不一样的。同样的问题在不同的时刻提出往往结果是不一样的。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2、对问题的思考角度<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;开发人员和非开发人员思考问题的角度通常是不一样的，这里笔者并是强调项目经理非要按照开发人员的思维考虑问题。比如项目&nbsp;&nbsp;经理&nbsp;&nbsp;在跟客户交流的时候是绝对不能用开发人员的思维跟客户交流的。但是同样的问题如果你在跟开发人员交流的时候，能够&nbsp;&nbsp;按照开发人员的思维方式表达出来那么结果是皆大欢喜。由此可见技术能力对项目经理是比较重要的。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3、统一的描述语言&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;目前的开发实践中似乎缺少一个统一的思维表达方式，RUP，UML似乎并不能完全解决我们的问题。&ldquo;用户不懂java，同样也不懂UML&rdquo;&nbsp;&nbsp;因此项目经理的技术能力就跟显得重要了。他能够把用户的要求用程序员的语言表达出来。<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 综上所述有管理才能的技术高手来担任项目经理还是比较合适的。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;讨论完中小型团队中的项目经理，下面我们来探讨一下中小型团队中的主力-程序员。他们应该如何组织呢？<br />笔者个人认为有以下几点可以参考<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、如果开发团队的人数小于5人，那么有项目经理直接领导。</p><p><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2、如果开发团队大于六个人可以将它们划分为若干个小组每个小组不少于三人不多于5人，同时每个小组设组长一名。这里笔者&nbsp;&nbsp;&nbsp;&nbsp; 提醒大家都是，在一个小组中组长的技术能力要高于组员，不要让小组中存在和组长技术能力不分上下的人。这样不利于小组&nbsp;&nbsp;&nbsp;&nbsp; 的和谐。诚然，现实的工作中有很多李云龙，赵刚似的好担当。但是那确实很好，我们没有必要冒这个风险。</p><p><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3、在项目的开发过程中有很多需要进行技术攻关的任务，这个任务通常是项目经理一人来搞定（条件是他有这个实力）或者有些团队会设定专门的技术攻关小组。笔者并不反对这一点做法，只是如果在条件允许的情况可以将这些任务适当的分配到各个小&nbsp;&nbsp;&nbsp;&nbsp; 组，这样能让每个开发团队的成员都有机会接触到新的东西，毕竟没有谁喜欢一直调用别人的API。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （未完待续）</p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://fx19800215.javaeye.com/blog/154597#comments" style="color:red;">已有 <strong>4</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 10 Jan 2008 00:14:53 +0800</pubDate>
        <link>http://fx19800215.javaeye.com/blog/154597</link>
        <guid>http://fx19800215.javaeye.com/blog/154597</guid>
      </item>
          <item>
        <title>关于java中使用webwervcie（xfire，axis）遇到的一个特殊字符导致错误的问题</title>
        <author>fx19800215</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fx19800215.javaeye.com">fx19800215</a>&nbsp;
                    链接：<a href="http://fx19800215.javaeye.com/blog/137767" style="color:red;">http://fx19800215.javaeye.com/blog/137767</a>&nbsp;
          发表时间: 2007年11月03日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          1、昨天我们解决了一个困挠了我们一个星期的问题，完成之后项目组的所有兄弟大吼一声，这个问题其实本身并不困难。现将问题已经解决的过程整理以供大家日后参考<br />&nbsp;&nbsp;&nbsp;&nbsp; 问题背景<br />&nbsp;&nbsp;&nbsp;&nbsp; 我们的整个硬件环境有5台服务器，其中四台服务器放着数据和操作系统还有我们的应用（一个j2ee的应用），还有一台机器是作为控制机来使用的。这5台机器中除了控制机外其他的机器都不能访问外网（客户的要求），但是系统有一个发送短信的功能，而短信网关是在外网，因此需要在控制机上面架设一个网关，通过该网关来发送短信。经过研究觉得我们采用webservice技术来实现这个网关，java中的webservie我们最熟悉的就是axis和xfire，因为我们的系统采用的是基于spring的架构，因此我们决定采用xfire。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 网关准备好了现在我们要开始发短信了，我们的短信内容是从运行营商现有的系统中取过来的，取数据的方式是采用socket的方式取的，对方的系统是采用c/c++开发的。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 网关好了，短信的内容也好了，现在改发短信了，也开始我们长达一个星期的炼狱历程。第一次发送的时候出现了错误：xfire提示数据报文里面有一个违法的字符，于是我们检查了报文，发现没有违法的字符，于是上xfire的论坛查和xfire相关的资料，发现没有这些问题，于是我们继续找（老板在崔啊），但是还是没有明确的结果。这个时候我们怀疑是不是操作系统的问题，于是换了操作系统，还是报错误。这个时候我们开始怀疑是不是xifre的问题，于是我们将webservice引擎更换成axis，结果还是报错，我们都无语了。到底是怎么回事呢。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这个时候我仔细分析了一下axis的错误日志（axis的错误日志比xifire要全面）发现axis提示是短信的最后一个字符是一个非法字符，可是短信内容的组合一个字符是一个”；“，这不是一个违法字符啊。突然我想起来，内容是我从客户的现有系统中通socket接口提取出来的<br />对方的系统是c/c++ 开发的，而c/c++和java在字符串结束的时候采用的换行符号是不一样的<br />而我们的短信是截取客户系统发过来的数据的最后一段，会不会是这个问题呢。于是我马上测试一下客户发过来的程序的最后一段的长度，果然和显示的长度相差一个字符。原来在客户系统传递过来的字符中，在字符的最后隐藏一个看不见的字符，就是这个字符导致了webservice报文的错误（冤枉了xfire，不过xfire也确实需要在日志的精确度上面下功夫了），于是修改程序将最后一个字符去掉，结果所有的错误都解决了。:-)<br />&nbsp;&nbsp;&nbsp;&nbsp; 通过这次经历得出一下体会<br />&nbsp;&nbsp;&nbsp; 1、在解决bug的时候，特别是程序中有多个层或者是和第三方系统有集成的时候，可以采用分段的方法来解决这个问题，即先确定问题出现在那个层，如果我们当时遇到错误的时候用一个字符串来代替客户的数据，说不定能早点发现问题<br />&nbsp;&nbsp;&nbsp; 2、在采用webservcie开发跨语言的系统的时候，移动考虑一下特殊字符在不用语言中的表现形式，因为webservice是基于文本的，对一些特殊字符很敏感。
          <br/><br/>
          <span style="color:red;">
            <a href="http://fx19800215.javaeye.com/blog/137767#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 03 Nov 2007 13:52:54 +0800</pubDate>
        <link>http://fx19800215.javaeye.com/blog/137767</link>
        <guid>http://fx19800215.javaeye.com/blog/137767</guid>
      </item>
          <item>
        <title>2006-11-18</title>
        <author>fx19800215</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fx19800215.javaeye.com">fx19800215</a>&nbsp;
                    链接：<a href="http://fx19800215.javaeye.com/blog/34847" style="color:red;">http://fx19800215.javaeye.com/blog/34847</a>&nbsp;
          发表时间: 2006年11月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><font face="Arial"><font face="Arial">快速上手Eclipse Eclipse快捷键指南</font><br />
<a href="http://dev.yesky.com/423/2510423.shtml">http://dev.yesky.com/423/2510423.shtml</a></font><font face="Arial"><br />
一些和eclipse相关的好文章<br />
<a href="http://dev.yesky.com/eclipse/index.shtml">http://dev.yesky.com/eclipse/index.shtml</a></font></p>
          <br/><br/>
          <span style="color:red;">
            <a href="http://fx19800215.javaeye.com/blog/34847#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 18 Nov 2006 13:24:32 +0800</pubDate>
        <link>http://fx19800215.javaeye.com/blog/34847</link>
        <guid>http://fx19800215.javaeye.com/blog/34847</guid>
      </item>
          <item>
        <title>2006-11-3</title>
        <author>fx19800215</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fx19800215.javaeye.com">fx19800215</a>&nbsp;
                    链接：<a href="http://fx19800215.javaeye.com/blog/32335" style="color:red;">http://fx19800215.javaeye.com/blog/32335</a>&nbsp;
          发表时间: 2006年11月03日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          2006-11-3 11:32<br /><br />1、今天在使用新公司系统的时候发现外网的系统的时候发现了一个比较愚蠢的错误报了一个原始的代码错误，但是我在使用内网的时候<br /> 		发现程序是对的，负责人告诉我这是因为外网的程序数据库中的一些初始数据没有设置。因此在开放过程中似乎应该将一些初始化的&nbsp;&nbsp;&nbsp;&nbsp; 数据已insert的语句的形式保存，在分模块开放的过程中，各个模块负责人负责维护这些语句，这些语句建议使用cvs（svn）等版本<br /> 		控制工具加以管理，在没有重构系统的时候都要重新生成这些数据<br /> 		<br />2、关于hibernate的多表查询问题<br />&nbsp;&nbsp; 在我的framework中，我将所有的关系放到了模型当中，但是这样的做法可以做到一个比较快速的响应，但是问题出来了，我如何关注<br />&nbsp;&nbsp; 效率问题呢，比如我在有些时候采用有连接似乎能更好的解决效率的问题，因此在框架的灵活性上面还是有很大的余地的，需要增加<br />&nbsp;&nbsp; 一个接口，这个接口用户可以自由的用HQL来写任何语句。那么这些东西的映射能否得到很好的解决吗<br /><br />3、hibernate配置文件中的 <br />&nbsp;&nbsp; &lt;class name="com.vnv.bank.hibernateBean.UserInfo" table="USER_INFO" schema="VNVBANK"><br />	 中schema是做什么用的。<br />	 <br />4、开源琴棋报表1.3.3发布 <br /><br />5、PowerStone(中文名——磐石)是一个基于Spring、Hibernate及其它若干开源框架和工具的，开放源代码的工作流管理系统； <br />		它实现了工作流管理联盟(WfMC)的Workflow参考模型中的接口1、2和5； <br />		它以开源的工作流编辑器——Enhydra JaWE(http://jawe.objectweb.org)作为流程定义工具。 <br />		<br />		PowerStone由以下模块构成： <br />		1、工作流引擎：负责解析用JaWE编辑生成的XPDL流程定义文档、调度流程流转、生成任务列表； <br />		2、管理控制台：提供工作流上传、部署、监控等后台管理功能，是一个WEB应用； <br />		3、任务列表：供最终用户使用来处理业务数据、与工作流引擎交互； <br />		4、用户权限系统：一个可替换的用户、权限管理系统，提供了基本的用户数据管理、基于角色的授权与访问控制和多系统单点登录功			能<br />		<br />		http://spring.jactiongroup.net/viewtopic.php?p=5195&amp;sid=dcdc5e0445c2c8c40bcbb5d70845f783<br />		<br />6、在多人合作的项目中数据库表结构的管理确实是个问题。<br /><br />7、关于spring配置文件的管理，个人建议采用节约型配置文件的管理办法，将系统分解成若干个模块，每个模块单独维护两个spring配置&nbsp;&nbsp;&nbsp; 文件一个 xxxxxDAO配置文件（配置DAO类），另一个为xxxService 文件（用来配置业务逻辑bean），<br />&nbsp;&nbsp; 一个项目采用一个sessionFactory<br />&nbsp;&nbsp; <br />8、以前的发布大包编译都是通过ANT来完成的，但是在开放的不是很方便，因此采用eclipse的做一站式的处理还是很有好处的。
          <br/><br/>
          <span style="color:red;">
            <a href="http://fx19800215.javaeye.com/blog/32335#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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;">Windows7在微软WinHEC 2008上揭开神秘面纱</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, 03 Nov 2006 15:45:52 +0800</pubDate>
        <link>http://fx19800215.javaeye.com/blog/32335</link>
        <guid>http://fx19800215.javaeye.com/blog/32335</guid>
      </item>
          <item>
        <title>关于hibernate事务的一个问题</title>
        <author>fx19800215</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fx19800215.javaeye.com">fx19800215</a>&nbsp;
                    链接：<a href="http://fx19800215.javaeye.com/blog/32243" style="color:red;">http://fx19800215.javaeye.com/blog/32243</a>&nbsp;
          发表时间: 2006年11月02日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          关于hibernate事务的一个问题，小弟在使用hibernate的时候（hibernate3.x）用session的saveOrupdate()方法，没有用 TransCation的 commit 方法 可是数据还是自动的提交到数据库中我在hibernate的配置文件中已经设置了 <br />&lt;property name="hibernate.connection.autocommit">false&lt;/property> 可是还是没有作用，请教高人教教小弟。
          <br/><br/>
          <span style="color:red;">
            <a href="http://fx19800215.javaeye.com/blog/32243#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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;">Windows7在微软WinHEC 2008上揭开神秘面纱</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, 02 Nov 2006 17:31:00 +0800</pubDate>
        <link>http://fx19800215.javaeye.com/blog/32243</link>
        <guid>http://fx19800215.javaeye.com/blog/32243</guid>
      </item>
          <item>
        <title>今天刚到新公司</title>
        <author>fx19800215</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fx19800215.javaeye.com">fx19800215</a>&nbsp;
                    链接：<a href="http://fx19800215.javaeye.com/blog/32059" style="color:red;">http://fx19800215.javaeye.com/blog/32059</a>&nbsp;
          发表时间: 2006年11月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          今天刚刚到新的公司，第一天开始上班，感觉还不错，准先好好的干一段时间在说。挣钱重要啊！嘻嘻
          <br/><br/>
          <span style="color:red;">
            <a href="http://fx19800215.javaeye.com/blog/32059#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 01 Nov 2006 22:42:27 +0800</pubDate>
        <link>http://fx19800215.javaeye.com/blog/32059</link>
        <guid>http://fx19800215.javaeye.com/blog/32059</guid>
      </item>
          <item>
        <title>Session详解 </title>
        <author>fx19800215</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fx19800215.javaeye.com">fx19800215</a>&nbsp;
                    链接：<a href="http://fx19800215.javaeye.com/blog/29350" style="color:red;">http://fx19800215.javaeye.com/blog/29350</a>&nbsp;
          发表时间: 2006年10月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          摘要：虽然session机制在web应用程序中被采用已经很长时间了，但是仍然有很多人不清楚session机制的本质，以至不能正确的应用这一技术。本文将详细讨论session的工作机制并且对在Java web application中应用session机制时常见的问题作出解答。<br /><br />目录：<br />一、术语session<br />二、HTTP协议与状态保持<br />三、理解cookie机制<br />四、理解session机制<br />五、理解javax.servlet.http.HttpSession<br />六、HttpSession常见问题<br />七、跨应用程序的session共享<br />八、总结<br />参考文档<br /><br />一、术语session<br />在我的经验里，session这个词被滥用的程度大概仅次于transaction，更加有趣的是transaction与session在某些语境下的含义是相同的。<br /><br />session，中文经常翻译为会话，其本来的含义是指有始有终的一系列动作/消息，比如打电话时从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个session。有时候我们可以看到这样的话“在一个浏览器会话期间，...”，这里的会话一词用的就是其本义，是指从一个浏览器窗口打开到关闭这个期间①。最混乱的是“用户（客户端）在一次会话期间”这样一句话，它可能指用户的一系列动作（一般情况下是同某个具体目的相关的一系列动作，比如从登录到选购商品到结账登出这样一个网上购物的过程，有时候也被称为一个transaction），然而有时候也可能仅仅是指一次连接，也有可能是指含义①，其中的差别只能靠上下文来推断②。<br /><br />然而当session一词与网络协议相关联时，它又往往隐含了“面向连接”和/或“保持状态”这样两个含义，“面向连接”指的是在通信双方在通信之前要先建立一个通信的渠道，比如打电话，直到对方接了电话通信才能开始，与此相对的是写信，在你把信发出去的时候你并不能确认对方的地址是否正确，通信渠道不一定能建立，但对发信人来说，通信已经开始了。“保持状态”则是指通信的一方能够把一系列的消息关联起来，使得消息之间可以互相依赖，比如一个服务员能够认出再次光临的老顾客并且记得上次这个顾客还欠店里一块钱。这一类的例子有“一个TCP session”或者“一个POP3 session”③。<br /><br />而到了web服务器蓬勃发展的时代，session在web开发语境下的语义又有了新的扩展，它的含义是指一类用来在客户端与服务器之间保持状态的解决方案④。有时候session也用来指这种解决方案的存储结构，如“把xxx保存在session里”⑤。由于各种用于web开发的语言在一定程度上都提供了对这种解决方案的支持，所以在某种特定语言的语境下，session也被用来指代该语言的解决方案，比如经常把Java里提供的javax.servlet.http.HttpSession简称为session⑥。<br /><br />鉴于这种混乱已不可改变，本文中session一词的运用也会根据上下文有不同的含义，请大家注意分辨。<br />在本文中，使用中文“浏览器会话期间”来表达含义①，使用“session机制”来表达含义④，使用“session”表达含义⑤，使用具体的“HttpSession”来表达含义⑥<br /><br />二、HTTP协议与状态保持<br />HTTP协议本身是无状态的，这与HTTP协议本来的目的是相符的，客户端只需要简单的向服务器请求下载某些文件，无论是客户端还是服务器都没有必要纪录彼此过去的行为，每一次请求之间都是独立的，好比一个顾客和一个自动售货机或者一个普通的（非会员制）大卖场之间的关系一样。<br /><br />然而聪明（或者贪心？）的人们很快发现如果能够提供一些按需生成的动态信息会使web变得更加有用，就像给有线电视加上点播功能一样。这种需求一方面迫使HTML逐步添加了表单、脚本、DOM等客户端行为，另一方面在服务器端则出现了CGI规范以响应客户端的动态请求，作为传输载体的HTTP协议也添加了文件上载、cookie这些特性。其中cookie的作用就是为了解决HTTP协议无状态的缺陷所作出的努力。至于后来出现的session机制则是又一种在客户端与服务器之间保持状态的解决方案。<br /><br />让我们用几个例子来描述一下cookie和session机制之间的区别与联系。笔者曾经常去的一家咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠，然而一次性消费5杯咖啡的机会微乎其微，这时就需要某种方式来纪录某位顾客的消费数量。想象一下其实也无外乎下面的几种方案：<br />1、该店的店员很厉害，能记住每位顾客的消费数量，只要顾客一走进咖啡店，店员就知道该怎么对待了。这种做法就是协议本身支持状态。<br />2、发给顾客一张卡片，上面记录着消费的数量，一般还有个有效期限。每次消费时，如果顾客出示这张卡片，则此次消费就会与以前或以后的消费相联系起来。这种做法就是在客户端保持状态。<br />3、发给顾客一张会员卡，除了卡号之外什么信息也不纪录，每次消费时，如果顾客出示该卡片，则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。<br /><br />由于HTTP协议是无状态的，而出于种种考虑也不希望使之成为有状态的，因此，后面两种方案就成为现实的选择。具体来说cookie机制采用的是在客户端保持状态的方案，而session机制采用的是在服务器端保持状态的方案。同时我们也看到，由于采用服务器端保持状态的方案在客户端也需要保存一个标识，所以session机制可能需要借助于cookie机制来达到保存标识的目的，但实际上它还有其他选择。<br /><br />三、理解cookie机制 <br />cookie机制的基本原理就如上面的例子一样简单，但是还有几个问题需要解决：“会员卡”如何分发；“会员卡”的内容；以及客户如何使用“会员卡”。<br /><br />正统的cookie分发是通过扩展HTTP协议来实现的，服务器通过在HTTP的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的cookie。然而纯粹的客户端脚本如JavaScript或者VBScript也可以生成cookie。<br /><br />而cookie的使用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器检查所有存储的cookie，如果某个cookie所声明的作用范围大于等于将要请求的资源所在的位置，则把该cookie附在请求资源的HTTP请求头上发送给服务器。意思是麦当劳的会员卡只能在麦当劳的店里出示，如果某家分店还发行了自己的会员卡，那么进这家店的时候除了要出示麦当劳的会员卡，还要出示这家店的会员卡。<br /><br />cookie的内容主要包括：名字，值，过期时间，路径和域。<br />其中域可以指定某一个域比如.google.com，相当于总店招牌，比如宝洁公司，也可以指定一个域下的具体某台机器比如www.google.com或者froogle.google.com，可以用飘柔来做比。<br />路径就是跟在域名后面的URL路径，比如/或者/foo等等，可以用某飘柔专柜做比。<br />路径与域合在一起就构成了cookie的作用范围。<br />如果不设置过期时间，则表示这个cookie的生命期为浏览器会话期间，只要关闭浏览器窗口，cookie就消失了。这种生命期为浏览器会话期的cookie被称为会话cookie。会话cookie一般不存储在硬盘上而是保存在内存里，当然这种行为并不是规范规定的。如果设置了过期时间，浏览器就会把cookie保存到硬盘上，关闭后再次打开浏览器，这些cookie仍然有效直到超过设定的过期时间。<br /><br />存储在硬盘上的cookie可以在不同的浏览器进程间共享，比如两个IE窗口。而对于保存在内存里的cookie，不同的浏览器有不同的处理方式。对于IE，在一个打开的窗口上按Ctrl-N（或者从文件菜单）打开的窗口可以与原窗口共享，而使用其他方式新开的IE进程则不能共享已经打开的窗口的内存cookie；对于Mozilla Firefox0.8，所有的进程和标签页都可以共享同样的cookie。一般来说是用javascript的window.open打开的窗口会与原窗口共享内存cookie。浏览器对于会话cookie的这种只认cookie不认人的处理方式经常给采用session机制的web应用程序开发者造成很大的困扰。<br /><br />下面就是一个goolge设置cookie的响应头的例子<br />HTTP/1.1 302 Found<br />Location: http://www.google.com/intl/zh-CN/<br />Set-Cookie: PREF=ID=0565f77e132de138:NW=1:TM=1098082649:LM=1098082649:S=KaeaCFPo49RiA_d8; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com<br />Content-Type: text/html<br /><br />&lt;!--[if !vml]-->&lt;!--[endif]--><br /><br /><br />这是使用HTTPLook这个HTTP Sniffer软件来俘获的HTTP通讯纪录的一部分<br /><br />&lt;!--[if !vml]-->&lt;!--[endif]--><br /><br /><br />浏览器在再次访问goolge的资源时自动向外发送cookie<br /><br />&lt;!--[if !vml]-->&lt;!--[endif]--><br /><br /><br />使用Firefox可以很容易的观察现有的cookie的值<br />使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理。<br /><br />&lt;!--[if !vml]-->&lt;!--[endif]--><br /><br /><br />IE也可以设置在接受cookie前询问<br /><br />&lt;!--[if !vml]-->&lt;!--[endif]--><br /><br /><br />这是一个询问接受cookie的对话框。<br /><br />四、理解session机制<br />session机制是一种服务器端的机制，服务器使用一种类似于散列表的结构（也可能就是使用散列表）来保存信息。<br /><br />当程序需要为某个客户端的请求创建一个session的时候，服务器首先检查这个客户端的请求里是否已包含了一个session标识 - 称为session id，如果已包含一个session id则说明以前已经为此客户端创建过session，服务器就按照session id把这个session检索出来使用（如果检索不到，可能会新建一个），如果客户端请求不包含session id，则为此客户端创建一个session并且生成一个与此session相关联的session id，session id的值应该是一个既不会重复，又不容易被找到规律以仿造的字符串，这个session id将被在本次响应中返回给客户端保存。<br /><br />保存这个session id的方式可以采用cookie，这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。一般这个cookie的名字都是类似于SEEESIONID，而。比如weblogic对于web应用程序生成的cookie，JSESSIONID=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764，它的名字就是JSESSIONID。<br /><br />由于cookie可以被人为的禁止，必须有其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。经常被使用的一种技术叫做URL重写，就是把session id直接附加在URL路径的后面，附加方式也有两种，一种是作为URL路径的附加信息，表现形式为http://...../xxx;jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764<br />另一种是作为查询字符串附加在URL后面，表现形式为http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764<br />这两种方式对于用户来说是没有区别的，只是服务器在解析的时候处理的方式不同，采用第一种方式也有利于把session id的信息和正常程序参数区分开来。<br />为了在整个交互过程中始终保持状态，就必须在每个客户端可能请求的路径后面都包含这个session id。<br /><br />另一种技术叫做表单隐藏字段。就是服务器会自动修改表单，添加一个隐藏字段，以便在表单提交时能够把session id传递回服务器。比如下面的表单<br />&lt;form name="testform" action="/xxx"><br />&lt;input type="text"><br />&lt;/form><br />在被传递给客户端之前将被改写成<br />&lt;form name="testform" action="/xxx"><br />&lt;input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764"><br />&lt;input type="text"><br />&lt;/form><br />这种技术现在已较少应用，笔者接触过的很古老的iPlanet6(SunONE应用服务器的前身)就使用了这种技术。<br />实际上这种技术可以简单的用对action应用URL重写来代替。<br /><br />在谈论session机制的时候，常常听到这样一种误解“只要关闭浏览器，session就消失了”。其实可以想象一下会员卡的例子，除非顾客主动对店家提出销卡，否则店家绝对不会轻易删除顾客的资料。对session来说也是一样的，除非程序通知服务器删除一个session，否则服务器会一直保留，程序一般都是在用户做log off的时候发个指令去删除session。然而浏览器从来不会主动在关闭之前通知服务器它将要关闭，因此服务器根本不会有机会知道浏览器已经关闭，之所以会有这种错觉，是大部分session机制都使用会话cookie来保存session id，而关闭浏览器后这个session id就消失了，再次连接服务器时也就无法找到原来的session。如果服务器设置的cookie被保存到硬盘上，或者使用某种手段改写浏览器发出的HTTP请求头，把原来的session id发送给服务器，则再次打开浏览器仍然能够找到原来的session。<br /><br />恰恰是由于关闭浏览器不会导致session被删除，迫使服务器为seesion设置了一个失效时间，当距离客户端上一次使用session的时间超过这个失效时间时，服务器就可以认为客户端已经停止了活动，才会把session删除以节省存储空间。<br /><br />五、理解javax.servlet.http.HttpSession<br />HttpSession是Java平台对session机制的实现规范，因为它仅仅是个接口，具体到每个web应用服务器的提供商，除了对规范支持之外，仍然会有一些规范里没有规定的细微差异。这里我们以BEA的Weblogic Server8.1作为例子来演示。<br /><br />首先，Weblogic Server提供了一系列的参数来控制它的HttpSession的实现，包括使用cookie的开关选项，使用URL重写的开关选项，session持久化的设置，session失效时间的设置，以及针对cookie的各种设置，比如设置cookie的名字、路径、域，cookie的生存时间等。<br /><br />一般情况下，session都是存储在内存里，当服务器进程被停止或者重启的时候，内存里的session也会被清空，如果设置了session的持久化特性，服务器就会把session保存到硬盘上，当服务器进程重新启动或这些信息将能够被再次使用，Weblogic Server支持的持久性方式包括文件、数据库、客户端cookie保存和复制。<br /><br />复制严格说来不算持久化保存，因为session实际上还是保存在内存里，不过同样的信息被复制到各个cluster内的服务器进程中，这样即使某个服务器进程停止工作也仍然可以从其他进程中取得session。<br /><br />cookie生存时间的设置则会影响浏览器生成的cookie是否是一个会话cookie。默认是使用会话cookie。有兴趣的可以用它来试验我们在第四节里提到的那个误解。<br /><br />cookie的路径对于web应用程序来说是一个非常重要的选项，Weblogic Server对这个选项的默认处理方式使得它与其他服务器有明显的区别。后面我们会专题讨论。<br /><br />关于session的设置参考[5] http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869<br /><br />六、HttpSession常见问题<br />（在本小节中session的含义为⑤和⑥的混合）<br /><br /><br />1、session在何时被创建<br />一个常见的误解是以为session在有客户端访问时就被创建，然而事实是直到某server端程序调用HttpServletRequest.getSession(true)这样的语句时才被创建，注意如果JSP没有显示的使用 &lt;%@page session="false"%> 关闭session，则JSP文件在编译成Servlet时将会自动加上这样一条语句HttpSession session = HttpServletRequest.getSession(true);这也是JSP中隐含的session对象的来历。<br /><br />由于session会消耗内存资源，因此，如果不打算使用session，应该在所有的JSP中关闭它。<br /><br />2、session何时被删除<br />综合前面的讨论，session在下列情况下被删除a.程序调用HttpSession.invalidate();或b.距离上一次收到客户端发送的session id时间间隔超过了session的超时设置;或c.服务器进程被停止（非持久session）<br /><br />3、如何做到在浏览器关闭时删除session<br />严格的讲，做不到这一点。可以做一点努力的办法是在所有的客户端页面里使用javascript代码window.oncolose来监视浏览器的关闭动作，然后向服务器发送一个请求来删除session。但是对于浏览器崩溃或者强行杀死进程这些非常规手段仍然无能为力。<br /><br />4、有个HttpSessionListener是怎么回事<br />你可以创建这样的listener去监控session的创建和销毁事件，使得在发生这样的事件时你可以做一些相应的工作。注意是session的创建和销毁动作触发listener，而不是相反。类似的与HttpSession有关的listener还有HttpSessionBindingListener，HttpSessionActivationListener和HttpSessionAttributeListener。<br /><br />5、存放在session中的对象必须是可序列化的吗<br />不是必需的。要求对象可序列化只是为了session能够在集群中被复制或者能够持久保存或者在必要时server能够暂时把session交换出内存。在Weblogic Server的session中放置一个不可序列化的对象在控制台上会收到一个警告。我所用过的某个iPlanet版本如果session中有不可序列化的对象，在session销毁时会有一个Exception，很奇怪。<br /><br />6、如何才能正确的应付客户端禁止cookie的可能性<br />对所有的URL使用URL重写，包括超链接，form的action，和重定向的URL，具体做法参见[6]<br />http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770<br /><br />7、开两个浏览器窗口访问应用程序会使用同一个session还是不同的session<br />参见第三小节对cookie的讨论，对session来说是只认id不认人，因此不同的浏览器，不同的窗口打开方式以及不同的cookie存储方式都会对这个问题的答案有影响。<br /><br />8、如何防止用户打开两个浏览器窗口操作导致的session混乱<br />这个问题与防止表单多次提交是类似的，可以通过设置客户端的令牌来解决。就是在服务器每次生成一个不同的id返回给客户端，同时保存在session里，客户端提交表单时必须把这个id也返回服务器，程序首先比较返回的id与保存在session里的值是否一致，如果不一致则说明本次操作已经被提交过了。可以参看《J2EE核心模式》关于表示层模式的部分。需要注意的是对于使用javascript window.open打开的窗口，一般不设置这个id，或者使用单独的id，以防主窗口无法操作，建议不要再window.open打开的窗口里做修改操作，这样就可以不用设置。<br /><br />9、为什么在Weblogic Server中改变session的值后要重新调用一次session.setValue<br />做这个动作主要是为了在集群环境中提示Weblogic Server session中的值发生了改变，需要向其他服务器进程复制新的session值。<br /><br />10、为什么session不见了<br />排除session正常失效的因素之外，服务器本身的可能性应该是微乎其微的，虽然笔者在iPlanet6SP1加若干补丁的Solaris版本上倒也遇到过；浏览器插件的可能性次之，笔者也遇到过3721插件造成的问题；理论上防火墙或者代理服务器在cookie处理上也有可能会出现问题。<br />出现这一问题的大部分原因都是程序的错误，最常见的就是在一个应用程序中去访问另外一个应用程序。我们在下一节讨论这个问题。<br /><br />七、跨应用程序的session共享<br /><br />常常有这样的情况，一个大项目被分割成若干小项目开发，为了能够互不干扰，要求每个小项目作为一个单独的web应用程序开发，可是到了最后突然发现某几个小项目之间需要共享一些信息，或者想使用session来实现SSO(single sign on)，在session中保存login的用户信息，最自然的要求是应用程序间能够访问彼此的session。<br /><br />然而按照Servlet规范，session的作用范围应该仅仅限于当前应用程序下，不同的应用程序之间是不能够互相访问对方的session的。各个应用服务器从实际效果上都遵守了这一规范，但是实现的细节却可能各有不同，因此解决跨应用程序session共享的方法也各不相同。<br /><br />首先来看一下Tomcat是如何实现web应用程序之间session的隔离的，从Tomcat设置的cookie路径来看，它对不同的应用程序设置的cookie路径是不同的，这样不同的应用程序所用的session id是不同的，因此即使在同一个浏览器窗口里访问不同的应用程序，发送给服务器的session id也可以是不同的。<br /><br />&lt;!--[if !vml]-->&lt;!--[endif]-->&lt;!--[if !vml]-->&lt;!--[endif]--><br /><br />根据这个特性，我们可以推测Tomcat中session的内存结构大致如下。<br /><br />&lt;!--[if !vml]-->&lt;!--[endif]--><br /><br />笔者以前用过的iPlanet也采用的是同样的方式，估计SunONE与iPlanet之间不会有太大的差别。对于这种方式的服务器，解决的思路很简单，实际实行起来也不难。要么让所有的应用程序共享一个session id，要么让应用程序能够获得其他应用程序的session id。<br /><br />iPlanet中有一种很简单的方法来实现共享一个session id，那就是把各个应用程序的cookie路径都设为/（实际上应该是/NASApp，对于应用程序来讲它的作用相当于根）。<br />&lt;session-info><br />&lt;path>/NASApp&lt;/path><br />&lt;/session-info><br /><br />需要注意的是，操作共享的session应该遵循一些编程约定，比如在session attribute名字的前面加上应用程序的前缀，使得setAttribute("name", "neo")变成setAttribute("app1.name", "neo")，以防止命名空间冲突，导致互相覆盖。<br /><br /><br />在Tomcat中则没有这么方便的选择。在Tomcat版本3上，我们还可以有一些手段来共享session。对于版本4以上的Tomcat，目前笔者尚未发现简单的办法。只能借助于第三方的力量，比如使用文件、数据库、JMS或者客户端cookie，URL参数或者隐藏字段等手段。<br /><br />我们再看一下Weblogic Server是如何处理session的。<br /><br />&lt;!--[if !vml]-->&lt;!--[endif]-->&lt;!--[if !vml]-->&lt;!--[endif]--><br /><br />从截屏画面上可以看到Weblogic Server对所有的应用程序设置的cookie的路径都是/，这是不是意味着在Weblogic Server中默认的就可以共享session了呢？然而一个小实验即可证明即使不同的应用程序使用的是同一个session，各个应用程序仍然只能访问自己所设置的那些属性。这说明Weblogic Server中的session的内存结构可能如下<br /><br />&lt;!--[if !vml]-->&lt;!--[endif]--><br /><br />对于这样一种结构，在session机制本身上来解决session共享的问题应该是不可能的了。除了借助于第三方的力量，比如使用文件、数据库、JMS或者客户端cookie，URL参数或者隐藏字段等手段，还有一种较为方便的做法，就是把一个应用程序的session放到ServletContext中，这样另外一个应用程序就可以从ServletContext中取得前一个应用程序的引用。示例代码如下，<br /><br />应用程序A<br />context.setAttribute("appA", session); <br /><br />应用程序B<br />contextA = context.getContext("/appA");<br />HttpSession sessionA = (HttpSession)contextA.getAttribute("appA"); <br /><br />值得注意的是这种用法不可移植，因为根据ServletContext的JavaDoc，应用服务器可以处于安全的原因对于context.getContext("/appA");返回空值，以上做法在Weblogic Server 8.1中通过。<br /><br />那么Weblogic Server为什么要把所有的应用程序的cookie路径都设为/呢？原来是为了SSO，凡是共享这个session的应用程序都可以共享认证的信息。一个简单的实验就可以证明这一点，修改首先登录的那个应用程序的描述符weblogic.xml，把cookie路径修改为/appA访问另外一个应用程序会重新要求登录，即使是反过来，先访问cookie路径为/的应用程序，再访问修改过路径的这个，虽然不再提示登录，但是登录的用户信息也会丢失。注意做这个实验时认证方式应该使用FORM，因为浏览器和web服务器对basic认证方式有其他的处理方式，第二次请求的认证不是通过session来实现的。具体请参看[7] secion 14.8 Authorization，你可以修改所附的示例程序来做这些试验。<br /><br />八、总结<br />session机制本身并不复杂，然而其实现和配置上的灵活性却使得具体情况复杂多变。这也要求我们不能把仅仅某一次的经验或者某一个浏览器，服务器的经验当作普遍适用的经验，而是始终需要具体情况具体分析。<br /><br />关于作者：<br />郎云鹏（dev2dev ID: hippiewolf），软件工程师，从事J2EE开发<br />电子邮件：langyunpeng@yahoo.com.cn<br />地址：大连软件园路31号科技大厦A座大连博涵咨询服务有限公司<br /><br />参考文档：<br />[1] Preliminary Specification http://wp.netscape.com/newsref/std/cookie_spec.html<br />[2] RFC2109 http://www.rfc-editor.org/rfc/rfc2109.txt<br />[3] RFC2965 http://www.rfc-editor.org/rfc/rfc2965.txt<br />[4] The Unofficial Cookie FAQ http://www.cookiecentral.com/faq/<br />[5] http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869<br />[6] http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770<br />[7] RFC2616 http://www.rfc-editor.org/rfc/rfc2616.txt<br /><br />代码下载：sampleApp.zip
          <br/><br/>
          <span style="color:red;">
            <a href="http://fx19800215.javaeye.com/blog/29350#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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;">Windows7在微软WinHEC 2008上揭开神秘面纱</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>Sun, 22 Oct 2006 14:42:32 +0800</pubDate>
        <link>http://fx19800215.javaeye.com/blog/29350</link>
        <guid>http://fx19800215.javaeye.com/blog/29350</guid>
      </item>
          <item>
        <title>LDAP </title>
        <author>fx19800215</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fx19800215.javaeye.com">fx19800215</a>&nbsp;
                    链接：<a href="http://fx19800215.javaeye.com/blog/29349" style="color:red;">http://fx19800215.javaeye.com/blog/29349</a>&nbsp;
          发表时间: 2006年10月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          原文：http://ldapman.org/articles/intro_to_ldap.html<br /><br />原文作者：Michael Donnelly<br /><br />翻译：Brimmer<br /><br />如果你在计算机行业工作，那么对LDAP可能早有耳闻了。想深入地了解LDAP吗？那么可以好好地读一下这篇文章。这篇介绍性的文章是一系列介绍如何在企业中设计、实现和集成LDAP环境的文章的头一篇。主要是先让你熟悉一下LDAP的基本概念，那些比较困难的细节问题将放到以后讨论。在这篇文章中我们将要介绍：<br /><br />什么是LDAP?<br /><br />什么时候该用LDAP存储数据？<br /><br />LDAP目录树的结构<br /><br />单独的LDAP记录<br /><br />作为例子的一个单独的数据项<br /><br />LDAP复制<br /><br />安全和访问控制<br /><br />现在LDAP技术不仅发展得很快而且也是激动人心的。在企业范围内实现LDAP可以让运行在几乎所有计算机平台上的所有的应用程序从LDAP目录中获取信息。LDAP目录中可以存储各种类型的数据：电子邮件地址、邮件路由信息、人力资源数据、公用密匙、联系人列表，等等。通过把LDAP目录作为系统集成中的一个重要环节，可以简化员工在企业内部查询信息的步骤，甚至连主要的数据源都可以放在任何地方。如果Oracle、Sybase、Informix或Microsoft SQL数据库中已经存储了类似的数据，那么LDAP和这些数据库到底有什么不同呢？是什么让它更具优势？请继续读下去吧！<br />什么是LDAP?<br /><br />LDAP的英文全称是Lightweight Directory Access Protocol，一般都简称为LDAP。它是基于X.500标准的，但是简单多了并且可以根据需要定制。与X.500不同，LDAP支持TCP/IP，这对访问Internet是必须的。LDAP的核心规范在RFC中都有定义，所有与LDAP相关的RFC都可以在LDAPman RFC网页中找到。<br />怎么使用LDAP这个术语呢？<br /><br />在日常交谈中，你可能会听到有些人这么说：“我们要把那些东西存在LDAP中吗？”，或者“从LDAP数据库中取出那些数据！”，又或者“我们怎么把LDAP和关系型数据库集成在一起？”。严格地说，LDAP根本不是数据库而是用来访问存储在信息目录（也就是LDAP目录）中的信息的协议。更为确切和正式的说法应该是象这样的：“通过使用LDAP，可以在信息目录的正确位置读取（或存储）数据”。但是，也没有必要吹毛求疵，尽管表达得不够准确，我们也都知道对方在说什么。<br />LDAP目录是数据库吗？<br /><br />就象Sybase、Oracle、Informix或Microsoft的数据库管理系统（DBMS）是用于处理查询和更新关系型数据库那样，LDAP服务器也是用来处理查询和更新LDAP目录的。换句话来说LDAP目录也是一种类型的数据库，但是不是关系型数据库。不象被设计成每分钟需要处理成百上千条数据变化的数据库，例如：在电子商务中经常用到的在线交易处理（OLTP）系统，LDAP主要是优化数据读取的性能。<br />LDAP目录的优势<br /><br />现在该说说LDAP目录到底有些什么优势了。现在LDAP的流行是很多因数共同作用的结果。我在这里说的不过是一些基本的原因，请你注意一下这不过是一小部分原因。<br /><br />可能LDAP最大的优势是：可以在任何计算机平台上，用很容易获得的而且数目不断增加的LDAP的客户端程序访问LDAP目录。而且也很容易定制应用程序为它加上LDAP的支持。<br /><br />LDAP协议是跨平台的和标准的协议，因此应用程序就不用为LDAP目录放在什么样的服务器上操心了。实际上，LDAP得到了业界的广泛认可，因为它是Internet的标准。产商都很愿意在产品中加入对LDAP的支持，因为他们根本不用考虑另一端（客户端或服务端）是怎么样的。LDAP服务器可以是任何一个开发源代码或商用的LDAP目录服务器（或者还可能是具有LDAP界面的关系型数据库），因为可以用同样的协议、客户端连接软件包和查询命令与LDAP服务器进行交互。与LDAP不同的是，如果软件产商想在软件产品中集成对DBMS的支持，那么通常都要对每一个数据库服务器单独定制。<br /><br />不象很多商用的关系型数据库，你不必为LDAP的每一个客户端连接或许可协议付费。<br /><br />大多数的LDAP服务器安装起来很简单，也容易维护和优化。<br /><br />LDAP服务器可以用“推”或“拉”的方法复制部分或全部数据，例如：可以把数据“推”到远程的办公室，以增加数据的安全性。复制技术是内置在LDAP服务器中的而且很容易配置。如果要在DBMS中使用相同的复制功能，数据库产商就会要你支付额外的费用，而且也很难管理。<br /><br />LDAP允许你根据需要使用ACI（一般都称为ACL或者访问控制列表）控制对数据读和写的权限。例如，设备管理员可以有权改变员工的工作地点和办公室号码，但是不允许改变记录中其它的域。ACI可以根据谁访问数据、访问什么数据、数据存在什么地方以及其它对数据进行访问控制。因为这些都是由LDAP目录服务器完成的，所以不用担心在客户端的应用程序上是否要进行安全检查。<br /><br />LDAP对于这样存储这样的信息最为有用，也就是数据需要从不同的地点读取，但是不需要经常更新。例如，这些信息存储在LDAP目录中是十分有效的：<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 公司员工的电话号码簿和组织结构图<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户的联系信息<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 计算机管理需要的信息，包括NIS映射、email假名，等等<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 软件包的配置信息<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 公用证书和安全密匙<br />什么时候该用LDAP存储数据？<br /><br />大多数的LDAP服务器都为读密集型的操作进行专门的优化。因此，当从LDAP服务器中读取数据的时候会比从专门为OLTP优化的关系型数据库中读取数据快一个数量级。也是因为专门为读的性能进行优化，大多数的LDAP目录服务器并不适合存储需要需要经常改变的数据。例如，用LDAP服务器来存储电话号码是一个很好的选择，但是它不能作为电子商务站点的数据库服务器。<br /><br />如果下面每一个问题的答案都是“是”，那么把数据存在LDAP中就是一个好主意。<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 需要在任何平台上都能读取数据吗？<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 每一个单独的记录项是不是每一天都只有很少的改变？<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以把数据存在平面数据库（flat database）而不是关系型数据库中吗？换句话来说，也就是不管什么范式不范式的，把所有东西都存在一个记录中（差不多只要满足第一范式）。<br /><br />最后一个问题可能会唬住一些人，其实用平面数据库去存储一些关系型的数据也是很一般的。例如，一条公司员工的记录就可以包含经理的登录名。用LDAP来存储这类信息是很方便的。一个简单的判断方法：如果可以把保数据存在一张张的卡片里，就可以很容易地把它存在LDAP目录里。<br />LDAP目录树的结构<br /><br />LDAP目录以树状的层次结构来存储数据。如果你对自顶向下的DNS树或UNIX文件的目录树比较熟悉，也就很容易掌握LDAP目录树这个概念了。就象DNS的主机名那样，LDAP目录记录的标识名（Distinguished Name，简称DN）是用来读取单个记录，以及回溯到树的顶部。后面会做详细地介绍。<br /><br />为什么要用层次结构来组织数据呢？原因是多方面的。下面是可能遇到的一些情况：<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果你想把所有的美国客户的联系信息都“推”到位于到西雅图办公室（负责营销）的LDAP服务器上，但是你不想把公司的资产管理信息“推”到那里。<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 你可能想根据目录树的结构给予不同的员工组不同的权限。在下面的例子里，资产管理组对“asset-mgmt”部分有完全的访问权限，但是不能访问其它地方。<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 把LDAP存储和复制功能结合起来，可以定制目录树的结构以降低对WAN带宽的要求。位于西雅图的营销办公室需要每分钟更新的美国销售状况的信息，但是欧洲的销售情况就只要每小时更新一次就行了。<br />刨根问底：基准DN<br /><br />LDAP目录树的最顶部就是根，也就是所谓的“基准DN”。基准DN通常使用下面列出的三种格式之一。假定我在名为FooBar的电子商务公司工作，这家公司在Internet上的名字是foobar.com。<br /><br />o="FooBar, Inc.", c=US<br /><br />（以X.500格式表示的基准DN）<br /><br />在这个例子中，o=FooBar, Inc. 表示组织名，在这里就是公司名的同义词。c=US 表示公司的总部在美国。以前，一般都用这种方式来表示基准DN。但是事物总是在不断变化的，现在所有的公司都已经（或计划）上Internet上。随着Internet的全球化，在基准DN中使用国家代码很容易让人产生混淆。现在，X.500格式发展成下面列出的两种格式。<br /><br />o=foobar.com<br /><br />（用公司的Internet地址表示的基准DN）<br /><br />这种格式很直观，用公司的域名作为基准DN。这也是现在最常用的格式。<br /><br />dc=foobar, dc=com<br /><br />（用DNS域名的不同部分组成的基准DN）<br /><br />就象上面那一种格式，这种格式也是以DNS域名为基础的，但是上面那种格式不改变域名（也就更易读），而这种格式把域名：foobar.com分成两部分 dc=foobar, dc=com。在理论上，这种格式可能会更灵活一点，但是对于最终用户来说也更难记忆一点。考虑一下foobar.com这个例子。当foobar.com和gizmo.com合并之后，可以简单的把“dc=com”当作基准DN。把新的记录放到已经存在的dc=gizmo, dc=com目录下，这样就简化了很多工作（当然，如果foobar.com和wocket.edu合并，这个方法就不能用了）。如果LDAP服务器是新安装的，我建议你使用这种格式。再请注意一下，如果你打算使用活动目录（Actrive Directory），Microsoft已经限制你必须使用这种格式。<br />更上一层楼：在目录树中怎么组织数据<br /><br />在UNIX文件系统中，最顶层是根目录（root）。在根目录的下面有很多的文件和目录。象上面介绍的那样，LDAP目录也是用同样的方法组织起来的。<br /><br />在根目录下，要把数据从逻辑上区分开。因为历史上（X.500）的原因，大多数LDAP目录用OU从逻辑上把数据分开来。OU表示“Organization Unit”，在X.500协议中是用来表示公司内部的机构：销售部、财务部，等等。现在LDAP还保留ou=这样的命名规则，但是扩展了分类的范围，可以分类为：ou=people, ou=groups, ou=devices，等等。更低一级的OU有时用来做更细的归类。例如：LDAP目录树（不包括单独的记录）可能会是这样的：<br /><br />&nbsp;&nbsp;&nbsp; dc=foobar, dc=com<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ou=customers<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ou=asia<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ou=europe<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ou=usa<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ou=employees<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ou=rooms<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ou=groups<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ou=assets-mgmt<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ou=nisgroups<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ou=recipes<br />单独的LDAP记录<br />DN是LDAP记录项的名字<br /><br />在LDAP目录中的所有记录项都有一个唯一的“Distinguished Name”，也就是DN。每一个LDAP记录项的DN是由两个部分组成的：相对DN（RDN）和记录在LDAP目录中的位置。<br /><br />RDN是DN中与目录树的结构无关的部分。在LDAP目录中存储的记录项都要有一个名字，这个名字通常存在cn（Common Name）这个属性里。因为几乎所有的东西都有一个名字，在LDAP中存储的对象都用它们的cn值作为RDN的基础。如果我把最喜欢的吃燕麦粥食谱存为一个记录，我就会用cn=Oatmeal Deluxe作为记录项的RDN。<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我的LDAP目录的基准DN是dc=foobar,dc=com<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我把自己的食谱作为LDAP的记录项存在ou=recipes<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我的LDAP记录项的RDN设为cn=Oatmeal Deluxe<br /><br />上面这些构成了燕麦粥食谱的LDAP记录的完整DN。记住，DN的读法和DNS主机名类似。下面就是完整的DN：<br /><br />cn=Oatmeal Deluxe,ou=recipes,dc=foobar,dc=com<br />举一个实际的例子来说明DN<br /><br />现在为公司的员工设置一个DN。可以用基于cn或uid（User ID），作为典型的用户帐号。例如，FooBar的员工Fran Smith（登录名：fsmith）的DN可以为下面两种格式：<br /><br />uid=fsmith,ou=employees,dc=foobar,dc=com<br /><br />（基于登录名）<br /><br />LDAP（以及X.500）用uid表示“User ID”，不要把它和UNIX的uid号混淆了。大多数公司都会给每一个员工唯一的登录名，因此用这个办法可以很好地保存员工的信息。你不用担心以后还会有一个叫Fran Smith的加入公司，如果Fran改变了她的名字（结婚？离婚？或宗教原因？），也用不着改变LDAP记录项的DN。<br /><br />cn=Fran Smith,ou=employees,dc=foobar,dc=com<br /><br />（基于姓名）<br /><br />可以看到这种格式使用了Common Name（CN）。可以把Common Name当成一个人的全名。这种格式有一个很明显的缺点就是：如果名字改变了，LDAP的记录就要从一个DN转移到另一个DN。但是，我们应该尽可能地避免改变一个记录项的DN。<br />定制目录的对象类型<br /><br />你可以用LDAP存储各种类型的数据对象，只要这些对象可以用属性来表示，下面这些是可以在LDAP中存储的一些信息：<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 员工信息：员工的姓名、登录名、口令、员工号、他的经理的登录名，邮件服务器，等等。<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 物品跟踪信息：计算机名、IP地址、标签、型号、所在位置，等等。<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 客户联系列表：客户的公司名、主要联系人的电话、传真和电子邮件，等等。<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 会议厅信息：会议厅的名字、位置、可以坐多少人、电话号码、是否有投影机。<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 食谱信息：菜的名字、配料、烹调方法以及准备方法。<br /><br />因为LDAP目录可以定制成存储任何文本或二进制数据，到底存什么要由你自己决定。LDAP目录用对象类型（object classes）的概念来定义运行哪一类的对象使用什么属性。在几乎所有的LDAP服务器中，你都要根据自己的需要扩展基本的LDAP目录的功能，创建新的对象类型或者扩展现存的对象类型。<br /><br />LDAP目录以一系列“属性对”的形式来存储记录项，每一个记录项包括属性类型和属性值（这与关系型数据库用行和列来存取数据有根本的不同）。下面是我存在LDAP目录中的一部分食谱记录：<br /><br />&nbsp; dn: cn=Oatmeal Deluxe, ou=recipes, dc=foobar, dc=com<br /><br />&nbsp; cn: Instant Oatmeal Deluxe<br /><br />&nbsp; recipeCuisine: breakfast<br /><br />&nbsp; recipeIngredient: 1 packet instant oatmeal<br /><br />&nbsp; recipeIngredient: 1 cup water<br /><br />&nbsp; recipeIngredient: 1 pinch salt<br /><br />&nbsp; recipeIngredient: 1 tsp brown sugar<br /><br />&nbsp; recipeIngredient: 1/4 apple, any type<br /><br />请注意上面每一种配料都作为属性recipeIngredient值。LDAP目录被设计成象上面那样为一个属性保存多个值的，而不是在每一个属性的后面用逗号把一系列值分开。<br /><br />因为用这样的方式存储数据，所以数据库就有很大的灵活性，不必为加入一些新的数据就重新创建表和索引。更重要的是，LDAP目录不必花费内存或硬盘空间处理“空”域，也就是说，实际上不使用可选择的域也不会花费你任何资源。<br />作为例子的一个单独的数据项<br /><br />让我们看看下面这个例子。我们用Foobar, Inc.的员工Fran Smith的LDAP记录。这个记录项的格式是LDIF，用来导入和导出LDAP目录的记录项。<br /><br />&nbsp; dn: uid=fsmith, ou=employees, dc=foobar, dc=com<br /><br />&nbsp; objectclass: person<br /><br />&nbsp; objectclass: organizationalPerson<br /><br />&nbsp; objectclass: inetOrgPerson<br /><br />&nbsp; objectclass: foobarPerson<br /><br />&nbsp; uid: fsmith<br /><br />&nbsp; givenname: Fran<br /><br />&nbsp; sn: Smith<br /><br />&nbsp; cn: Fran Smith<br /><br />&nbsp; cn: Frances Smith<br /><br />&nbsp; telephonenumber: 510-555-1234<br /><br />&nbsp; roomnumber: 122G<br /><br />&nbsp; o: Foobar, Inc.<br /><br />&nbsp; mailRoutingAddress: fsmith@foobar.com<br /><br />&nbsp; mailhost: mail.foobar.com<br /><br />&nbsp; userpassword: {crypt}3x1231v76T89N<br /><br />&nbsp; uidnumber: 1234<br /><br />&nbsp; gidnumber: 1200<br /><br />&nbsp; homedirectory: /home/fsmith<br /><br />&nbsp; loginshell: /usr/local/bin/bash<br /><br />属性的值在保存的时候是保留大小写的，但是在默认情况下搜索的时候是不区分大小写的。某些特殊的属性（例如，password）在搜索的时候需要区分大小写。<br /><br />让我们一点一点地分析上面的记录项。<br /><br />dn: uid=fsmith, ou=employees, dc=foobar, dc=com<br /><br />这是Fran的LDAP记录项的完整DN，包括在目录树中的完整路径。LDAP（和X.500）使用uid（User ID），不要把它和UNIX的uid号混淆了。<br /><br />&nbsp; objectclass: person<br /><br />&nbsp; objectclass: organizationalPerson<br /><br />&nbsp; objectclass: inetOrgPerson<br /><br />&nbsp; objectclass: foobarPerson<br /><br />可以为任何一个对象根据需要分配多个对象类型。person对象类型要求cn（common name）和sn（surname）这两个域不能为空。persion对象类型允许有其它的可选域，包括givenname、telephonenumber，等等。organizational Person给person加入更多的可选域，inetOrgPerson又加入更多的可选域（包括电子邮件信息）。最后，foobarPerson是为Foobar定制的对象类型，加入了很多定制的属性。<br /><br />&nbsp; uid: fsmith<br /><br />&nbsp; givenname: Fran<br /><br />&nbsp; sn: Smith<br /><br />&nbsp; cn: Fran Smith<br /><br />&nbsp; cn: Frances Smith<br /><br />&nbsp; telephonenumber: 510-555-1234<br /><br />&nbsp; roomnumber: 122G<br /><br />&nbsp; o: Foobar, Inc.<br /><br />以前说过了，uid表示User ID。当看到uid的时候，就在脑袋里想一想“login”。<br /><br />请注意CN有多个值。就象上面介绍的，LDAP允许某些属性有多个值。为什么允许有多个值呢？假定你在用公司的LDAP服务器查找Fran的电话号码。你可能只知道她的名字叫Fran，但是对人力资源处的人来说她的正式名字叫做Frances。因为保存了她的两个名字，所以用任何一个名字检索都可以找到Fran的电话号码、电子邮件和办公房间号，等等。<br /><br />&nbsp; mailRoutingAddress: fsmith@foobar.com<br /><br />&nbsp; mailhost: mail.foobar.com<br /><br />就象现在大多数的公司都上网了，Foobar用Sendmail发送邮件和处理外部邮件路由信息。Foobar把所有用户的邮件信息都存在LDAP中。最新版本的Sendmail支持这项功能。<br /><br />&nbsp; Userpassword: {crypt}3x1231v76T89N<br /><br />&nbsp; uidnumber: 1234<br /><br />&nbsp; gidnumber: 1200<br /><br />&nbsp; gecos: Frances Smith<br /><br />&nbsp; homedirectory: /home/fsmith<br /><br />&nbsp; loginshell: /usr/local/bin/bash<br /><br />注意，Foobar的系统管理员把所有用户的口令映射信息也都存在LDAP中。FoobarPerson类型的对象具有这种能力。再注意一下，用户口令是用UNIX的口令加密格式存储的。UNIX的uid在这里为uidnumber。提醒你一下，关于如何在LDAP中保存NIS信息，有完整的一份RFC。在以后的文章中我会谈一谈NIS的集成。<br />LDAP复制<br /><br />LDAP服务器可以使用基于“推”或者“拉”的技术，用简单或基于安全证书的安全验证，复制一部分或者所有的数据。<br /><br />例如，Foobar有一个“公用的”LDAP服务器，地址为ldap.foobar.com，端口为389。Netscape Communicator的电子邮件查询功能、UNIX的“ph”命令要用到这个服务器，用户也可以在任何地方查询这个服务器上的员工和客户联系信息。公司的主LDAP服务器运行在相同的计算机上，不过端口号是1389。<br /><br />你可能即不想让员工查询资产管理或食谱的信息，又不想让信息技术人员看到整个公司的LDAP目录。为了解决这个问题，Foobar有选择地把子目录树从主LDAP服务器复制到“公用”LDAP服务器上，不复制需要隐藏的信息。为了保持数据始终是最新的，主目录服务器被设置成即时“推”同步。这些种方法主要是为了方便，而不是安全，因为如果有权限的用户想查询所有的数据，可以用另一个LDAP端口。<br /><br />假定Foobar通过从奥克兰到欧洲的低带宽数据的连接用LDAP管理客户联系信息。可以建立从ldap.foobar.com:1389到munich-ldap.foobar.com:389的数据复制，象下面这样：<br /><br />&nbsp; periodic pull: ou=asia,ou=customers,o=sendmail.com<br /><br />&nbsp; periodic pull: ou=us,ou=customers,o=sendmail.com<br /><br />&nbsp; immediate push: ou=europe,ou=customers,o=sendmail.com<br /><br />“拉”连接每15分钟同步一次，在上面假定的情况下足够了。“推”连接保证任何欧洲的联系信息发生了变化就立即被“推”到Munich。<br /><br />用上面的复制模式，用户为了访问数据需要连接到哪一台服务器呢？在Munich的用户可以简单地连接到本地服务器。如果他们改变了数据，本地的LDAP服务器就会把这些变化传到主LDAP服务器。然后，主LDAP服务器把这些变化“推”回本地的“公用”LDAP服务器保持数据的同步。这对本地的用户有很大的好处，因为所有的查询（大多数是读）都在本地的服务器上进行，速度非常快。当需要改变信息的时候，最终用户不需要重新配置客户端的软件，因为LDAP目录服务器为他们完成了所有的数据交换工作。<br />安全和访问控制<br /><br />LDAP提供很复杂的不同层次的访问控制或者ACI。因这些访问可以在服务器端控制，这比用客户端的软件保证数据的安全可安全多了。<br /><br />用LDAP的ACI，可以完成：<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 给予用户改变他们自己的电话号码和家庭地址的权限，但是限制他们对其它数据（如，职务名称，经理的登录名，等等）只有“只读”权限。<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 给予“HR-admins”组中的所有人权限以改变下面这些用户的信息：经理、工作名称、员工号、部门名称和部门号。但是对其它域没有写权限。<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 禁止任何人查询LDAP服务器上的用户口令，但是可以允许用户改变他或她自己的口令。<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 给予经理访问他们上级的家庭电话的只读权限，但是禁止其他人有这个权限。<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 给予“host-admins”组中的任何人创建、删除和编辑所有保存在LDAP服务器中的与计算机主机有关的信息<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 通过Web，允许“foobar-sales”组中的成员有选择地给予或禁止他们自己读取一部分客户联系数据的读权限。这将允许他们把客户联系信息下载到本地的笔记本电脑或个人数字助理（PDA）上。（如果销售人员的软件都支持LDAP，这将非常有用）<br /><br />l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 通过Web，允许组的所有者删除或添加他们拥有的组的成员。例如：可以允许销售经理给予或禁止销售人员改变Web页的权限。也可以允许邮件假名（mail aliase）的所有者不经过IT技术人员就直接从邮件假名中删除或添加用户。“公用”的邮件列表应该允许用户从邮件假名中添加或删除自己（但是只能是自己）。也可以对IP地址或主机名加以限制。例如，某些域只允许用户IP地址以192.168.200.*开头的有读的权限，或者用户反向查找DNS得到的主机名必须为*.foobar.com。<br /><br />这不过是让你了解一下可以对LDAP目录进行怎样的访问控制，实际上真正实现起来需要做的工作比这多得多。在以后的文章中我会详细地讨论访问控制。
          <br/><br/>
          <span style="color:red;">
            <a href="http://fx19800215.javaeye.com/blog/29349#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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;">Windows7在微软WinHEC 2008上揭开神秘面纱</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>Sun, 22 Oct 2006 14:36:24 +0800</pubDate>
        <link>http://fx19800215.javaeye.com/blog/29349</link>
        <guid>http://fx19800215.javaeye.com/blog/29349</guid>
      </item>
          <item>
        <title>JavaScript实用的一些技巧 </title>
        <author>fx19800215</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fx19800215.javaeye.com">fx19800215</a>&nbsp;
                    链接：<a href="http://fx19800215.javaeye.com/blog/29348" style="color:red;">http://fx19800215.javaeye.com/blog/29348</a>&nbsp;
          发表时间: 2006年10月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          1. oncontextmenu="window.event.returnValue=false" 将彻底屏蔽鼠标右键<br />&lt;table border oncontextmenu=return(false)>&lt;td>no&lt;/table> 可用于Table <br /><br />2. &lt;body onselectstart="return false"> 取消选取、防止复制<br /><br />3. onpaste="return false" 不准粘贴<br /><br />4. oncopy="return false;" oncut="return false;" 防止复制<br /><br />5. &lt;link rel="Shortcut Icon" href="favicon.ico"> IE地址栏前换成自己的图标<br /><br />6. &lt;link rel="Bookmark" href="favicon.ico"> 可以在收藏夹中显示出你的图标<br /><br />7. &lt;input style="ime-mode:disabled"> 关闭输入法<br /><br />8. 永远都会带着框架<br />&lt;script language="JavaScript">&lt;!--<br />if (window == top)top.location.href = "frames.htm"; //frames.htm为框架网页<br />// -->&lt;/script><br /><br />9. 防止被人frame<br />&lt;SCRIPT LANGUAGE=JAVASCRIPT>&lt;!-- <br />if (top.location != self.location)top.location=self.location;<br />// -->&lt;/SCRIPT><br /><br />10. 网页将不能被另存为<br />&lt;noscript>&lt;iframe src=*.html>&lt;/iframe>&lt;/noscript> <br /><br />11. &lt;input type=button value=查看网页源代码 <br />onclick="window.location = "view-source:"+ "http://www.pconline.com.cn""><br /><br />12.删除时确认<br />&lt;a href="javascript:if(confirm("确实要删除吗?"))location="boos.asp?&amp;areyou=删除&amp;page=1"">删除&lt;/a> <br /><br />13. 取得控件的绝对位置<br />//Javascript<br />&lt;script language="Javascript"><br />function getIE(e){<br />var t=e.offsetTop;<br />var l=e.offsetLeft;<br />while(e=e.offsetParent){<br />t+=e.offsetTop;<br />l+=e.offsetLeft;<br />}<br />alert("top="+t+"/nleft="+l);<br />}<br />&lt;/script><br /><br />//VBScript<br />&lt;script language="VBScript">&lt;!--<br />function getIE()<br />dim t,l,a,b<br />set a=document.all.img1<br />t=document.all.img1.offsetTop<br />l=document.all.img1.offsetLeft<br />while a.tagName&lt;>"BODY"<br />set a = a.offsetParent<br />t=t+a.offsetTop<br />l=l+a.offsetLeft<br />wend<br />msgbox "top="&amp;t&amp;chr(13)&amp;"left="&amp;l,64,"得到控件的位置"<br />end function<br />-->&lt;/script><br /><br />14. 光标是停在文本框文字的最后<br />&lt;script language="javascript"><br />function cc()<br />{<br />var e = event.srcElement;<br />var r =e.createTextRange();<br />r.moveStart("character",e.value.length);<br />r.collapse(true);<br />r.select();<br />}<br />&lt;/script><br />&lt;input type=text name=text1 value="123" onfocus="cc()"><br /><br />15. 判断上一页的来源<br />javascript:<br />document.referrer<br /><br />16. 最小化、最大化、关闭窗口<br />&lt;object id=hh1 classid="clsid:ADB880A6-D8FF-11CF-9377-00AA003B7A11"> <br />&lt;param name="Command" value="Minimize">&lt;/object><br />&lt;object id=hh2 classid="clsid:ADB880A6-D8FF-11CF-9377-00AA003B7A11"> <br />&lt;param name="Command" value="Maximize">&lt;/object><br />&lt;OBJECT id=hh3 classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11"><br />&lt;PARAM NAME="Command" VALUE="Close">&lt;/OBJECT><br />&lt;input type=button value=最小化 onclick=hh1.Click()><br />&lt;input type=button value=最大化 onclick=hh2.Click()><br />&lt;input type=button value=关闭 onclick=hh3.Click()><br />本例适用于IE<br /><br />17.屏蔽功能键Shift,Alt,Ctrl<br />&lt;script><br />function look(){ <br />if(event.shiftKey) <br />alert("禁止按Shift键!"); //可以换成ALT　CTRL<br />} <br />document.onkeydown=look; <br />&lt;/script><br /><br />18. 网页不会被缓存<br />&lt;META HTTP-EQUIV="pragma" CONTENT="no-cache"><br />&lt;META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate"><br />&lt;META HTTP-EQUIV="expires" CONTENT="Wed, 26 Feb 1997 08:21:57 GMT"><br />或者&lt;META HTTP-EQUIV="expires" CONTENT="0"><br /><br />19.怎样让表单没有凹凸感？<br />&lt;input type=text style="border:1 solid #000000"> <br />或<br />&lt;input type=text style="border-left:none; border-right:none; border-top:none; border-bottom: <br /><br />1 solid #000000">&lt;/textarea><br /><br />20.&lt;div>&lt;span>&amp;&lt;layer>的区别？ <br />&lt;div>(division)用来定义大段的页面元素，会产生转行 <br />&lt;span>用来定义同一行内的元素，跟&lt;div>的唯一区别是不产生转行 <br />&lt;layer>是ns的标记，ie不支持，相当于&lt;div><br /><br /><br /><br />21.让弹出窗口总是在最上面:<br />&lt;body onblur="this.focus();"><br /><br />22.不要滚动条? <br />让竖条没有: <br />&lt;body style="overflow:scroll;overflow-y:hidden"> <br />&lt;/body> <br />让横条没有: <br />&lt;body style="overflow:scroll;overflow-x:hidden"> <br />&lt;/body> <br />两个都去掉？更简单了 <br />&lt;body scroll="no"> <br />&lt;/body> <br /><br />23.怎样去掉图片链接点击后，图片周围的虚线？<br />&lt;a href="#" onFocus="this.blur()">&lt;img src="logo.jpg" border=0>&lt;/a><br /><br />24.电子邮件处理提交表单<br />&lt;form name="form1" method="post" action="mailto:****@***.com" enctype="text/plain"> <br />&lt;input type=submit><br />&lt;/form><br /><br />25.在打开的子窗口刷新父窗口的代码里如何写？<br />window.opener.location.reload()<br /><br />26.如何设定打开页面的大小<br />&lt;body onload="top.resizeTo(300,200);"><br />打开页面的位置&lt;body onload="top.moveBy(300,200);"><br /><br />27.在页面中如何加入不是满铺的背景图片,拉动页面时背景图不动 <br />&lt;STYLE> <br />body <br />{background-image:url(logo.gif); background-repeat:no-repeat; <br />background-position:center;background-attachment: fixed} <br />&lt;/STYLE> <br /><br />28. 检查一段字符串是否全由数字组成<br />&lt;script language="Javascript">&lt;!--<br />function checkNum(str){return str.match(//D/)==null}<br />alert(checkNum("1232142141"))<br />alert(checkNum("123214214a1"))<br />// -->&lt;/script><br /><br />29. 获得一个窗口的大小<br />document.body.clientWidth; document.body.clientHeight<br /><br />30. 怎么判断是否是字符<br />if (/[^/x00-/xff]/g.test(s)) alert("含有汉字");<br />else alert("全是字符");<br /><br />31.TEXTAREA自适应文字行数的多少<br />&lt;textarea rows=1 name=s1 cols=27 onpropertychange="this.style.posHeight=this.scrollHeight"><br />&lt;/textarea><br /><br />32. 日期减去天数等于第二个日期<br />&lt;script language=Javascript><br />function cc(dd,dadd)<br />{<br />//可以加上错误处理<br />var a = new Date(dd)<br />a = a.valueOf()<br />a = a - dadd * 24 * 60 * 60 * 1000<br />a = new Date(a)<br />alert(a.getFullYear() + "年" + (a.getMonth() + 1) + "月" + a.getDate() + "日")<br />}<br />cc("12/23/2002",2)<br />&lt;/script><br /><br />33. 选择了哪一个Radio<br />&lt;HTML>&lt;script language="vbscript"><br />function checkme()<br />for each ob in radio1<br />if ob.checked then window.alert ob.value<br />next<br />end function<br />&lt;/script>&lt;BODY><br />&lt;INPUT name="radio1" type="radio" value="style" checked>Style<br />&lt;INPUT name="radio1" type="radio" value="barcode">Barcode<br />&lt;INPUT type="button" value="check" onclick="checkme()"><br />&lt;/BODY>&lt;/HTML><br /><br />34.脚本永不出错<br />&lt;SCRIPT LANGUAGE="JavaScript"> <br />&lt;!-- Hide <br />function killErrors() { <br />return true; <br />} <br />window.onerror = killErrors; <br />// --> <br />&lt;/SCRIPT><br /><br />35.ENTER键可以让光标移到下一个输入框<br />&lt;input onkeydown="if(event.keyCode==13)event.keyCode=9"><br /><br />36. 检测某个网站的链接速度：<br />把如下代码加入&lt;body>区域中:<br />&lt;script language=Javascript><br />tim=1<br />setInterval("tim++",100)<br />b=1<br />var autourl=new Array()<br />autourl[1]="www.njcatv.net"<br />autourl[2]="javacool.3322.net"<br />autourl[3]="www.sina.com.cn"<br />autourl[4]="www.nuaa.edu.cn"<br />autourl[5]="www.cctv.com"<br />function butt(){<br />document.write("&lt;form name=autof>")<br />for(var i=1;i&lt;autourl.length;i++)<br />document.write("&lt;input type=text name=txt"+i+" size=10 value=测试中……> =》&lt;input type=text <br />name=url"+i+" size=40> =》&lt;input type=button value=GO <br /><br />onclick=window.open(this.form.url"+i+".value)>&lt;br>")<br />document.write("&lt;input type=submit value=刷新>&lt;/form>")<br />}<br />butt()<br />function auto(url){<br />document.forms[0]["url"+b].value=url<br />if(tim>200)<br />{document.forms[0]["txt"+b].value="链接超时"}<br />else<br />{document.forms[0]["txt"+b].value="时间"+tim/10+"秒"}<br />b++<br />}<br />function run(){for(var i=1;i&lt;autourl.length;i++)document.write("&lt;img src=http://"+autourl+"/"+Math.random()+" width=1 height=1 <br /><br />onerror=auto("http://"+autourl+"")>")}<br />run()&lt;/script><br /><br />37. 各种样式的光标<br />auto ：标准光标<br />default ：标准箭头<br />hand ：手形光标<br />wait ：等待光标<br />text ：I形光标<br />vertical-text ：水平I形光标<br />no-drop ：不可拖动光标<br />not-allowed ：无效光标<br />help ：?帮助光标<br />all-scroll ：三角方向标<br />move ：移动标<br />crosshair ：十字标<br />e-resize<br />n-resize<br />nw-resize<br />w-resize<br />s-resize<br />se-resize<br />sw-resize<br /><br />38.页面进入和退出的特效<br />进入页面&lt;meta http-equiv="Page-Enter" content="revealTrans(duration=x, transition=y)"><br />推出页面&lt;meta http-equiv="Page-Exit" content="revealTrans(duration=x, transition=y)">&nbsp; <br />这个是页面被载入和调出时的一些特效。duration表示特效的持续时间，以秒为单位。transition表示使用哪种特效，取值为1-23:<br />　　0 矩形缩小 <br />　　1 矩形扩大 <br />　　2 圆形缩小<br />　　3 圆形扩大 <br />　　4 下到上刷新 <br />　　5 上到下刷新<br />　　6 左到右刷新 <br />　　7 右到左刷新 <br />　　8 竖百叶窗<br />　　9 横百叶窗 <br />　　10 错位横百叶窗 <br />　　11 错位竖百叶窗<br />　　12 点扩散 <br />　　13 左右到中间刷新 <br />　　14 中间到左右刷新<br />　　15 中间到上下<br />　　16 上下到中间 <br />　　17 右下到左上<br />　　18 右上到左下 <br />　　19 左上到右下 <br />　　20 左下到右上<br />　　21 横条 <br />　　22 竖条 <br />　　23 以上22种随机选择一种<br /><br />39.在规定时间内跳转<br />&lt;META http-equiv=V="REFRESH" content="5;URL=http://www.51js.com"> <br /><br />40.网页是否被检索<br />&lt;meta name="ROBOTS" content="属性值"><br />　　其中属性值有以下一些:<br />　　属性值为"all": 文件将被检索，且页上链接可被查询；<br />　　属性值为"none": 文件不被检索，而且不查询页上的链接；<br />　　属性值为"index": 文件将被检索；<br />　　属性值为"follow": 查询页上的链接；<br />　　属性值为"noindex": 文件不检索，但可被查询链接；<br />　　属性值为"nofollow": 文件不被检索，但可查询页上的链接。
          <br/><br/>
          <span style="color:red;">
            <a href="http://fx19800215.javaeye.com/blog/29348#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</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;">Windows7在微软WinHEC 2008上揭开神秘面纱</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>Sun, 22 Oct 2006 14:34:08 +0800</pubDate>
        <link>http://fx19800215.javaeye.com/blog/29348</link>
        <guid>http://fx19800215.javaeye.com/blog/29348</guid>
      </item>
      </channel>
</rss>