<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>一起飞的更高</title>
    <description>我要飞翔  不断超越自己  不断超越梦想</description>
    <link>http://isky.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>JBPM  JPA  Spring  闹别扭了  ==============</title>
        <author>isky</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://isky.javaeye.com">isky</a>&nbsp;
          链接：<a href="http://isky.javaeye.com/blog/206646" style="color:red;">http://isky.javaeye.com/blog/206646</a>&nbsp;
          发表时间: 2008年06月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp; <span style="font-size: medium; font-family: 楷体;">各位大家好，&nbsp; jbpm的ORM映射用的是Hibernate&nbsp;&nbsp;&nbsp; 如果我想整合到我现有的项目JPA+Spring，&nbsp; 那么该如何处理？</span></p>
          <br/>
          <span style="color:red;">
            <a href="http://isky.javaeye.com/blog/206646#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</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>Sat, 21 Jun 2008 13:55:15 +0800</pubDate>
        <link>http://isky.javaeye.com/blog/206646</link>
        <guid>http://isky.javaeye.com/blog/206646</guid>
      </item>
      <item>
        <title>JBoss  SeamTest   断言问题 </title>
        <author>isky</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://isky.javaeye.com">isky</a>&nbsp;
          链接：<a href="http://isky.javaeye.com/blog/200558" style="color:red;">http://isky.javaeye.com/blog/200558</a>&nbsp;
          发表时间: 2008年06月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>package org.jboss.seam.example.registration.test;</p>
<p>import javax.faces.context.FacesContext;</p>
<p>import org.jboss.seam.mock.SeamTest;<br />import org.testng.annotations.Test;</p>
<p>public class RegisterTest extends SeamTest<br />{<br />&nbsp;&nbsp; <br />&nbsp;&nbsp; @Test<br />&nbsp;&nbsp; public void testLogin() throws Exception<br />&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new FacesRequest("/register.jspx") {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected void processValidations() throws Exception<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; validateValue("#{user.username}", "1ovthafew");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; validateValue("#{user.name}", "Gavin King");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; validateValue("#{user.password}", "secret");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assert !isValidationFailure();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected void updateModelValues() throws Exception<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setValue("#{user.username}", "1ovthafew");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setValue("#{user.name}", "Gavin King");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setValue("#{user.password}", "secret");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected void invokeApplication()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assert invokeMethod("#{register.register}").equals("/registered.jspx");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setOutcome("/registered.jspx");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected void afterRequest()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assert isInvokeApplicationComplete();<br /><span style="color: #ff0000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: medium;">&nbsp;&nbsp;&nbsp; assert&nbsp; !isRenderResponseBegun();</span></strong></span></p>
<p><strong><span style="font-size: medium; color: #ff0000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #0000ff;">&nbsp;assert&nbsp; IsRenderResponseComplete();</span></span></strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }.run();</p>
<p>&nbsp;</p>
<p><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new NonFacesRequest("/registered.jspx")<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected void renderResponse()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assert getValue("#{user.username}").equals("1ovthafew");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assert getValue("#{user.password}").equals("secret");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assert getValue("#{user.name}").equals("Gavin King");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }.run();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new FacesRequest("/register.jspx") {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected void processValidations() throws Exception<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; validateValue("#{user.username}", "1ovthafew");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; validateValue("#{user.name}", "Gavin A King");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; validateValue("#{user.password}", "password");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected void updateModelValues() throws Exception<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setValue("#{user.username}", "1ovthafew");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setValue("#{user.name}", "Gavin A King");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setValue("#{user.password}", "password");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected void invokeApplication()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assert invokeMethod("#{register.register}")==null;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected void renderResponse() throws Exception<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assert FacesContext.getCurrentInstance().getMessages().hasNext();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected void afterRequest()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assert isInvokeApplicationComplete();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assert isRenderResponseComplete();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }.run();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp; }<br />&nbsp;&nbsp; <br />}</p>
<p>&nbsp;</p>
<p>以上是seam框架包自带的registration项目的测试用例， 上面带红线的一行代码，<strong><span style="font-size: medium; color: #ff0000;">isRenderResponseBegun(); 我浏览SeamTest的时候发现</span></strong></p>
<p>&nbsp; private void renderResponsePhase() throws Exception<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; phases.beforePhase(new PhaseEvent(facesContext, PhaseId.RENDER_RESPONSE, MockLifecycle.INSTANCE));</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; updateConversationId();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; renderResponseBegun = true;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; renderResponse();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; renderResponseComplete = true;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; facesContext.getApplication().getStateManager().saveView(facesContext);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; updateConversationId();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; finally<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; phases.afterPhase(new PhaseEvent(facesContext, PhaseId.RENDER_RESPONSE, MockLifecycle.INSTANCE));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p><span style="font-size: medium; color: #ff0000;"><strong>在这个阶段的时候 renderResponseBegun = true;&nbsp; 为什么断言中是false？&nbsp;即（是 assert&nbsp; <span style="color: #0000ff;">!</span>isRenderResponseBegun();&nbsp; 而不是assert&nbsp;isRenderResponseBegun()？ ） 请问高手解释一下？</strong></span></p>
<p><span style="font-size: medium; color: #ff0000;"><strong>这行代码</strong></span><span style="font-size: medium; color: #ff0000;"><strong>&nbsp;&nbsp;<span style="color: #0000ff;">assert&nbsp; isRenderResponseComplete();</span> 是我添加上的，但是测试的时候断言失败， 也就是&nbsp;&nbsp;renderResponseComplete值是false，明明在上面的阶段设置为true了 ？&nbsp; 这又是怎么回事呀？<br /></strong></span><br /><strong><span style="font-size: medium; color: #0000ff;"><br /></span></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: medium; color: #0000ff;"><br /></span></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
          <br/>
          <span style="color:red;">
            <a href="http://isky.javaeye.com/blog/200558#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/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 05 Jun 2008 16:13:35 +0800</pubDate>
        <link>http://isky.javaeye.com/blog/200558</link>
        <guid>http://isky.javaeye.com/blog/200558</guid>
      </item>
      <item>
        <title>能将PPT放映时投影仪看全屏而电脑上看备注的详细方法</title>
        <author>isky</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://isky.javaeye.com">isky</a>&nbsp;
          链接：<a href="http://isky.javaeye.com/blog/195648" style="color:red;">http://isky.javaeye.com/blog/195648</a>&nbsp;
          发表时间: 2008年05月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h2>能将PPT放映时投影仪看全屏而电脑上看备注的详细方法</h2>
<div class="t_msgfont" id="postmessage_41966">前言：大家在看此篇文章之前心中是不是一直存有一个疑问，那就是office组件中的powerpoint（PPT）制作中的&ldquo;备注&rdquo;到底有何作用？<br /><img src="http://file.hxblog.net/attachments/month_0503/ppt/001.jpg" border="0" alt="" /><br />在工作中经常用PPT放映演示给客户进行讲演，也见识过专业讲师和IT销售给我介绍产品，使用的也是PPT。但是几乎所有人的PPT使用方式还是停留在投影机上放什么，演讲者的laptop上也显示什么，演讲者要么看自己的laptop的屏幕，要么看墙上的投 影。&ldquo;备注&rdquo;就彻底失去了作用，因为根本看不见。<br />出于纳闷，我就询问了几个号称是office高手这个问题，&ldquo;备注&rdquo;写了是给谁看的，有什么作用？<br />高手给出的答案竟然是&ldquo;备注&rdquo;用来给演讲者回忆讲演思路，或者此PPT给别人的时候别人讲演前可以先了解一下制作此PPT的作者的思路意图。 <br /><br />这些都是PPT的常规用法，或者说并不怎么正确的用法，下面我给大家介绍如何高效的使用PPT进行演讲，并且充分利用&ldquo;备注&rdquo;的作用，以期为受众作出最出色的讲解。<br /><br />下面我就开始了。下面做演示用的PPT涉及某安全厂商，原因是我手头做的比较好的PPT而且备注写的比较详细的也就这份了，我并没有用于商业用途，我也不是该厂商员工，特别声明。<br /><img src="http://file.hxblog.net/attachments/month_0503/ppt/002.jpg" border="0" alt="" /><br />第一步，在你的laptop的显示属性中进行设置。<br /><br />如图所示，在连接了外部显示器或者投影仪的情况下，点击&ldquo;2&rdquo;号屏幕，并按照图中高亮标注处选中&ldquo;将windows桌面扩展到该显示器&rdquo;同时设置适当的分辨率。<br />单击&ldquo;应用&rdquo;，就可以看到如下的效果。<br /><img src="http://file.hxblog.net/attachments/month_0503/ppt/003.jpg" border="0" onclick="zoom(this)" alt="" style="cursor: pointer;" width="770" /><br />由于家里没有投影做演示，就用了一台上了年纪的CRT做示意。从两个屏幕可以看见不同的显示内容，左面的CRT的屏幕正是要给演讲受众看的。这样，下面的观众就不会看见演讲者的笔记本里面装了什么东西，演讲者可以根据自己的意愿把需要给观众看的放映出来， 而不是把演讲者的所有操作都放映出来。（这个好处我就不多说了，有过类似经历的朋友想必深有体会）<br /><br />第二步，打开你需要演讲的PPT进行放映前的准备工作。<br /><img src="http://file.hxblog.net/attachments/month_0503/ppt/004.jpg" border="0" alt="" /><br />选择放映的设置<br /><img src="http://file.hxblog.net/attachments/month_0503/ppt/005.jpg" border="0" alt="" /><br />在图中高亮的部分选中&ldquo;显示演讲者视图&rdquo;（这个是重点）<br />单击确定后就完成了设置。<br /><br />第三步，开始放映。<br /><img src="http://file.hxblog.net/attachments/month_0503/ppt/006.jpg" border="0" alt="" /><br />点击图中的位置，或者直接按&ldquo;F5&rdquo;。两者的区别是，F5从头开始放映，而图示按钮是从当前slide开始往后放映。<br /><br />最后，观看效果<br /><img src="http://file.hxblog.net/attachments/month_0503/ppt/007.jpg" border="0" onclick="zoom(this)" alt="" style="cursor: pointer;" width="770" /><br />这个就是演讲者看到的画面，下面高亮的部分就是&ldquo;备注&rdquo;的内容。<br />&middot;分析这个视图，演讲者不仅可以看见每个slide的预览；<br />&middot;还可以知晓下一张PPT的大致内容（标题）；<br />&middot;可以不用准备，直接阅读&ldquo;备注&rdquo;（对于新手和临场不知所错的朋友比较适合）；<br />&middot;可以很好的控制演讲时间；<br />&middot;在进行slide选择（非正常流程）的时候，可以点击&ldquo;黑屏&rdquo;，这样观众就看不到你在进行何种&ldquo;胡乱操作&rdquo;了。<br /><img src="http://file.hxblog.net/attachments/month_0503/ppt/008.jpg" border="0" onclick="zoom(this)" alt="" style="cursor: pointer;" width="770" /><br />从观众处，看见的效果就如上所示。</div>
          <br/>
          <span style="color:red;">
            <a href="http://isky.javaeye.com/blog/195648#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/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 22 May 2008 14:35:26 +0800</pubDate>
        <link>http://isky.javaeye.com/blog/195648</link>
        <guid>http://isky.javaeye.com/blog/195648</guid>
      </item>
      <item>
        <title>C#    Reflection</title>
        <author>isky</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://isky.javaeye.com">isky</a>&nbsp;
          链接：<a href="http://isky.javaeye.com/blog/193557" style="color:red;">http://isky.javaeye.com/blog/193557</a>&nbsp;
          发表时间: 2008年05月16日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>using System;<br />using System.Collections.Generic;<br />using System.Text;<br />using System.Reflection;<br />namespace detegate<br />{</p>
<p><br />&nbsp;&nbsp;&nbsp; class Data<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //成绩数据以字段呈现<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Score score1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Score score2;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Score score3;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Score score4;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //学生数据以属性呈现<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private Student student1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private Student student2;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //课程数据以方法返回<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private Course course1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private Course course2;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //属性封装了方法<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Student Student1<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; get { return student1; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Student Student2<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; get { return student2; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 初始化数据</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Data()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; student1 = new Student("小猪",Gender.男);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; student2 = new Student("小成",Gender.女);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; course1 = new Course("课程A","老王");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; course2 = new Course("课程B","老李");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; score1 = new Score(student1,course1,91);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; score2 = new Score(student1, course2, 81);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; score3 = new Score(student2, course1, 92);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; score4 = new Score(student2, course2, 82);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //返回课程数据<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Course getCourse1()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return course1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Course getCourse2()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return course2;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; enum Gender<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 男,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 女<br />&nbsp;&nbsp;&nbsp; }</p>
<p><br />&nbsp;&nbsp;&nbsp; class Student<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public string studentName;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Gender studentGender;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Student(string studentName, Gender studentGender)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.studentName = studentName;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.studentGender = studentGender;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; }</p>
<p><br />&nbsp;&nbsp;&nbsp; class Course<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public string courseName;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public string courseTeacherName;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Course(string courseName, string courseTeacherName)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.courseName = courseName;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.courseTeacherName = courseTeacherName;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; class Score<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Student student;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Course course;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public int mark;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Score(Student student, Course course,int&nbsp; mark)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.student = student;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.course = course;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.mark = mark;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; class ReflectionHelper<br />&nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 使用反射遍历对象的成员</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void listMenber(Data date)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine("\n----------------------遍历对象的成员------------------------------");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine("\n成员名\t\t成员类型\t\t声明成员的类");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //表示获取成员的MemberInfo数组<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MemberInfo[] arr = date.GetType().GetMembers();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach(MemberInfo&nbsp;&nbsp; mi&nbsp; in&nbsp; arr)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine(string.Format ("{0}\t{1}\t{2}",<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mi.Name.PadRight(10,' '),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mi.MemberType.ToString().PadRight(10, ' '),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mi.DeclaringType .ToString ().PadRight(10,' ')));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //使用反射遍历对象的字段<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void ListField(Data data)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine("\n---------------------遍历对象字段----------------------------------");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine("\n姓名\t性别\t课程名\t授课老师\t成绩");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 获取表示字段的FiledInfo类型的数组<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FieldInfo[] arr = data.GetType().GetFields();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach (FieldInfo fi in arr)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Score score = (Score)fi.GetValue(data);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine(string.Format ("{0}\t{1}\t{2}\t{3}\t{4}",<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; score.student.studentName,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; score.student.studentGender,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; score.course.courseName,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; score.course.courseTeacherName,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; score.mark));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //使用反射遍历对象的属性<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void ListProperty(Data data)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine("\n---------------------遍历对象属性----------------------------------");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine("\n姓名\t性别");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //获取属性 PropertyInfo数组<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PropertyInfo[]&nbsp; arr =&nbsp; data.GetType().GetProperties();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach(PropertyInfo&nbsp; pi in&nbsp;&nbsp;&nbsp; arr)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //读取字段的值<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Student&nbsp; student&nbsp; = (Student) pi.GetValue(data,null);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine(string.Format ("{0}\t{1}",student.studentName,student.studentGender));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //使用反射遍历对象的方法<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void ListMethod(Data data)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine("\n---------------------遍历对象方法----------------------------------");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine("\n课程名\t授课老师");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp; 获取方法数组<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MethodInfo[] arr = data.GetType().GetMethods();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach (MethodInfo mi in arr)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mi.Name.IndexOf("getCourse") &gt; -1)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Course cource = mi.Invoke(data,null)&nbsp; as&nbsp; Course;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine(string.Format("{0}\t{1}",<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cource.courseName ,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cource.courseTeacherName));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static&nbsp; void Main(string[] args)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Data data = new Data();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ReflectionHelper reflectHelper = new ReflectionHelper();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reflectHelper.listMenber(data);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reflectHelper.ListField(data);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reflectHelper.ListProperty(data);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reflectHelper.ListMethod(data);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }<br />}</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://isky.javaeye.com/blog/193557#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/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</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>Fri, 16 May 2008 10:52:11 +0800</pubDate>
        <link>http://isky.javaeye.com/blog/193557</link>
        <guid>http://isky.javaeye.com/blog/193557</guid>
      </item>
      <item>
        <title>地震了</title>
        <author>isky</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://isky.javaeye.com">isky</a>&nbsp;
          链接：<a href="http://isky.javaeye.com/blog/192238" style="color:red;">http://isky.javaeye.com/blog/192238</a>&nbsp;
          发表时间: 2008年05月12日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>大家有没有感觉到地址了？？？？？？？？？？？？？？？？？？？？？？ 我们这发生地震了&nbsp; </p>
          <br/>
          <span style="color:red;">
            <a href="http://isky.javaeye.com/blog/192238#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/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 12 May 2008 14:52:04 +0800</pubDate>
        <link>http://isky.javaeye.com/blog/192238</link>
        <guid>http://isky.javaeye.com/blog/192238</guid>
      </item>
      <item>
        <title>DotNet软件开发框架 </title>
        <author>isky</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://isky.javaeye.com">isky</a>&nbsp;
          链接：<a href="http://isky.javaeye.com/blog/187571" style="color:red;">http://isky.javaeye.com/blog/187571</a>&nbsp;
          发表时间: 2008年04月28日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;以我个人的能力，没有足够的时间和资源自行开发一套完整的平台。在已有的众多开源项目中选择若干优秀的项目进行整合。&ldquo;站在巨人肩膀上&rdquo;是牛顿有一句名言.，同样适合我们的IT行业。</p>
<div>我对平台的技术架构的构想，是采用开源的ORM框架做数据持久层， Asp.net没有合适的Web层框架，就采用Asp.net的Code-behind方式编写代码，数据持久层同Web表现层之间的连接采用IOC的容器。</div>
<div>1、 开源框架选择：</div>
<div>数据持久层Nhibernate和IbatisNet这两个都是非常优秀的数据持久层，Nhibernate是优秀的Hibernate的dotNet移植版本，在开源社区具有非常高的人气，IbatisNet是Data Mapper框架，也是JAVA版的Ibatis的移植版本，在dotnet的开源社区一样是非常受欢迎的一个工具。Nhibernate用于支持非常好的面向对象的设计的模型，IbatisNet用于支持应用程序的移植（已经存在数据库，处于生产状态），这两个框架对开发人员的要求。这样就具有更大的弹性。IOC容器Spring.Net和Castle，这是两个dotnet非常优秀的IOC容器。Spring.Net同样是Java的Spring 的移植版本，目前的版本是0.6，Castle则是dotnet下出现新的IOC容器,它的功能，成熟度方面比Spring.Net好得多，框架中准备采用Castle.最后的平台的技术架构就是Nhibernate/IbatisNet + Castle + ASP.NET</div>
<div>2、 架构整合：</div>
<div>Web层的Asp.net负责数据输入输出, 响应用户事件，及输入校验的工作，Web层上如何得到Nhibernate的Session和IbatisNet的SqlMapper?本架构中的DAO,Service以及 Nhibernate的Session和IbatisNet的SqlMapper都是通过Castle进行管理，Web层如何得到Castle IOC容器的实例呢，参照文章<a href="http://isky.javaeye.com/archive/2005/10/28/264103.html" class="postTitle2" id="viewpost1_TitleUrl"><span style="color: #1d58d1;">在asp.net页面上得到Castle容器的实例</span></a> 。Asp.net页面通过Service处理业务逻辑，Service负责use case逻辑, domain相关的逻辑委托给domain model去实现. Service通过DAO完成对domain model的持久化工作. Service负责数据库事务和NHibernate Session/IbatisNet SqlMapper的管理。Domain model负责表示问题域的数据，DAO使用Nhibernate/IbatisNet持久化数据以及查询. 在实现DAO时, 我们使用了Castle的Nhibernate/IbatisNet DAO Support,极大地简化了代码, 很多方法都只用简单的一行完成。这样的架构优点很明显, 层次清晰, 各层的职责也明确, 便于分层设计与开发, 结合mock和Castle的IOC, unit test也是非常容易的. 而且后台(Service, domain model and DAO)的代码不依赖于Asp.net框架，同样的代码可以在Web App也可以在WinForm上面使用，只需更换UI层。</div>
<div>&nbsp;</div>
<div>使用的框架工具的链接</div>
<div><a href="http://www.castleproject.org/castle/show/HomePage"><span style="color: #1d58d1;">http://www.castleproject.org/castle/show/HomePage</span></a></div>
<div><a href="http://nhibernate.sourceforge.net/"><span style="color: #1d58d1;">http://nhibernate.sourceforge.net/</span></a></div>
<div><a href="http://sourceforge.net/projects/ibatisnet/"><span style="color: #1d58d1;">http://sourceforge.net/projects/ibatisnet/</span></a></div>
<div></div>
<div><span style="color: #0000ff;"><span style="text-decoration: underline;">另外这里有一篇精彩文章</span><a href="http://shanyou.cnblogs.com/simonw/archive/2005/04/27/146185.html"><span style="color: #1d58d1;">应用系统架构设计</span></a></span><a href="javascript:void(0);/*1114857718849*/"><span style="color: #1d58d1;"> </span></a></div>
<div id="MySignature">自由、创新、研究、探索&hellip;&hellip; <br />Url: <a href="http://shanyou.cnblogs.com/"><span style="color: #1d58d1;">http://shanyou.cnblogs.com </span></a><br />website: <a href="http://www.openbeta.cn/"><span style="color: #1d58d1;">http://www.openbeta.cn</span></a> </div>
          <br/>
          <span style="color:red;">
            <a href="http://isky.javaeye.com/blog/187571#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/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 28 Apr 2008 15:30:47 +0800</pubDate>
        <link>http://isky.javaeye.com/blog/187571</link>
        <guid>http://isky.javaeye.com/blog/187571</guid>
      </item>
      <item>
        <title>应用系统架构设计-补全篇</title>
        <author>isky</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://isky.javaeye.com">isky</a>&nbsp;
          链接：<a href="http://isky.javaeye.com/blog/187525" style="color:red;">http://isky.javaeye.com/blog/187525</a>&nbsp;
          发表时间: 2008年04月28日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h2><span>应用系统架构设计-补全篇</span></h2>
<h2><span><span style="font-size: small;">原文地址：</span><a href="http://www.cnblogs.com/simonw/archive/2005/10/27/263145.html"><span style="font-size: x-small;">http://www.cnblogs.com/simonw/archive/2005/10/27/263145.html</span></a></span></h2>
<p>我们在做着表面上看似是对于各种不同应用的开发，其实背后所对应的架构设计都是相对稳定的。在一个好的架构下编程，不仅对于开发人员是一件赏心悦目的事情，更重要的是软件能够表现出一个健康的姿态；而架构设计的不合理，不仅让开发人员受苦受难，软件本身的生命周期更是受到严重威胁。这里我将针对在微软<span lang="EN-US">dotNet</span><span>平台上做应用开发的系统架构设计做一个粗浅的讨论。</span></p>
<p><span lang="EN-US">&nbsp;</span></p>
<p align="center"><span>总体设计图</span></p>
<p align="center"><span lang="EN-US">&nbsp;<img src="http://www.cnblogs.com/images/cnblogs_com/simonw/应用系统架构设计-总体架构图.jpg" height="432" align="baseline" hspace="5" alt="" width="251" /></span></p>
<p align="center">&nbsp;</p>
<p><span lang="EN-US">&nbsp;</span></p>
<h2><span>表示层</span></h2>
<p><span>表示层由</span><span lang="EN-US">UI</span><span>（</span><span lang="EN-US">User Interface</span><span>）和</span><span lang="EN-US">UI</span><span>控制逻辑组成。</span></p>
<ul>
<li><span lang="EN-US"><span lang="EN-US">UI</span><span>（</span><span lang="EN-US">User Interface</span><span>）</span> </span></li>
</ul>
<p><span lang="EN-US"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>UI</span><span>是客户端的用户界面，负责从用户方接收命令，请求，数据，传递给业务层处理，然后将结果呈现出来。根据客户端的不同我们大体将应用程序分为</span><span lang="EN-US">BS</span><span>（</span><span lang="EN-US">Browser-Server</span><span>）</span> <span>浏览器结构，</span><span lang="EN-US">CS</span><span>（</span><span lang="EN-US">Client-Server</span><span>）桌面客户端结构。</span></p>
<p><span lang="EN-US"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>BS</span><span>的优点是无需操心客户端，只需要部署维护好服务器即可。</span><span lang="EN-US">CS</span><span>的优点在于强大的界面交互表达能力。</span><span lang="EN-US">RIA</span><span>（</span><span lang="EN-US">Rich Internet Application</span><span>）是为了融合这两种结构优点的一种技术，它依赖在客户端一次性安装一个通用解释器之后即获得强大的界面交互表达能力和无需部署具体客户端的方便性。具体的实现技术很多，例如微软的</span><span lang="EN-US">SmartClient</span><span>，</span><span lang="EN-US"> Avalon</span><span>；</span><span lang="EN-US"> Macromedia</span><span>的</span><span lang="EN-US">Flex</span><span>；以</span><span lang="EN-US">JS</span><span>为基础的</span><span lang="EN-US">Bindows</span><span>；</span><span lang="EN-US">Ajax</span><span>等等很多。</span><span lang="EN-US">&nbsp;</span></p>
<ul>
<li><span lang="EN-US"><span lang="EN-US">UI</span><span>控制逻辑</span> </span></li>
</ul>
<p><span lang="EN-US"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>UI</span><span>控制逻辑负责处理</span><span lang="EN-US">UI</span><span>和业务层之间的数据交互，</span><span lang="EN-US">UI</span><span>之间状态流程的控制，同时负责简单的数据验证和格式化等功能。具体的说在</span><span lang="EN-US">dotNet</span><span>事件驱动的编程模型下，</span><span lang="EN-US">UI</span><span>控制逻辑被自然的实现在了事件函数中，例如</span><span lang="EN-US">PageLoad</span><span>事件函数，</span><span lang="EN-US">ButtonClick</span><span>事件函数。在这些事件函数中，主要任务就是做</span><span lang="EN-US">UI</span><span>控件与业务实体的数据交换与业务调用，但面对大量的数据交换工作量与维护量就成了最大的问题。而在复杂应用的系统中，状态与流程的管理是必须要考虑的因素，它包含了界面与业务两方面。如果不加以封装的直接写在事件函数中将导致业务依赖表示层。下面分别讨论这两个问题。</span><span lang="EN-US">&nbsp;</span></p>
<blockquote dir="ltr" style="margin-right: 0px;">
<p><span lang="EN-US"><span lang="EN-US">1.UI</span><span>与业务实体之间的数据交互</span></span></p>
</blockquote>
<p><span><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>此阶段负责数据交换的业务实体我把它称为</span><span lang="EN-US">DTO</span><span>（</span><span lang="EN-US">Data Transfer Object</span><span>），但需要说明的是这里的</span><span lang="EN-US">DTO</span><span>并不是只包含数据的业务对象，它仍然包含必要的方法是完整的业务实体。处理输入时我们从</span><span lang="EN-US">UI</span><span>控件的获得数据填入</span><span lang="EN-US">DTO</span><span>再向下传播，处理输出时用户发出请求业务层会将数据以</span><span lang="EN-US">DTO</span><span>的形式返出再赋给</span><span lang="EN-US">UI</span><span>控件展现。因此需要一种方式来自动解决这样的来回赋值问题。</span><span lang="EN-US">Java</span><span>下</span><span lang="EN-US">Structs</span><span>的</span><span lang="EN-US">Formbean</span><span>对此问题提供了一定支持，而遗憾的是</span><span lang="EN-US">dotNet</span><span>下的不少控件虽然支持数据绑定但仍然没有一个现成完整的解决办法。一种比较简单的方式是自己设计一个</span><span lang="EN-US">Adapter</span><span>按照某种映射关系来自动处理这样的绑定，这样的映射关系最好是</span><span lang="EN-US">UI</span><span>控件与</span><span lang="EN-US">DTO</span><span>属性的事先命名约定，以此种方式的约定作为映射关系无需增加任何配置文件和配置工作即可实现。例如你的一个输入人名的</span><span lang="EN-US">Textbox</span><span>命名为</span><span lang="EN-US">txtUserName</span><span>，而我的业务实体属性命名为</span><span lang="EN-US">UserName</span><span>，这样就可以通过字符串的查找来找到对应。</span><span lang="EN-US">&nbsp;</span></p>
<blockquote dir="ltr" style="margin-right: 0px;">
<p><span lang="EN-US"><span>2.状态与流程的管理</span></span></p>
</blockquote>
<p><span><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>复杂业务方面的状态与流程可以通过一些工作流引擎来解决，微软最近独立发布了自己的工作流引擎有兴趣的朋友可以去看看。一般更多的情况是需要解决界面上状态与流程的管理。耦合再表示层中是不可取的办法。</span><span lang="EN-US">MVC</span><span>（</span><span lang="EN-US"><a href="http://www.microsoft.com/china/MSDN/library/architecture/patterns/esp/DesMVC.mspx"><span style="color: #770000;">Model-View-Controller</span></a></span><span>）模式提供了实现这一目标的方法。</span><span lang="EN-US">Controller</span><span>是整个方案的核心，它是一个流程管理器，来自</span><span lang="EN-US">UI</span><span>所有的命令与数据经过</span><span lang="EN-US">Controller</span><span>分发给业务层或其他</span><span lang="EN-US">UI</span><span>，这样我们可以把流程，权限等逻辑单独封装，例如配置文件中，达到最大化的业务重用。</span><span lang="EN-US">dotNet</span><span>下</span><span lang="EN-US">MVC</span><span>的方案并不像</span><span lang="EN-US">Java</span><span>下有那么多选择，目前有以下几种选择：</span></p>
<p><span>微软的</span><span lang="EN-US"><a href="http://msdn.microsoft.com/library/en-us/dnpag/html/uipab.asp"><span style="color: #770000;">UIPAB</span></a></span><span>，它可以处理</span><span lang="EN-US">bs</span><span>，</span><span lang="EN-US">cs</span><span>下的流程跳转，可以使得相同的业务系统有</span><span lang="EN-US">webform</span><span>和</span><span lang="EN-US">winform</span><span>不同的展现方式。</span></p>
<p><span>开源的</span><span lang="EN-US"><a href="http://mavnet.sourceforge.net/"><span style="color: #770000;">Mavrick.Net</span></a></span><span>，它只适用于</span><span lang="EN-US">Asp.Net</span><span>应用程序，它对流程，国际化，页面包装，</span><span lang="EN-US">xslt</span><span>页面转换提供了很好的支持。</span></p>
<p><span>开源的</span><span lang="EN-US"><a href="http://lattis.sourceforge.net/"><span style="color: #770000;">Lattis</span></a></span><span>，功能比较单一，同样只适用于</span><span lang="EN-US">Asp.Net</span><span>应用程序。</span></p>
<p><span lang="EN-US">&nbsp;</span></p>
<h2><span>业务层</span></h2>
<p><span><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>业务层封装了实际业务逻辑，包含数据验证，事物处理，权限处理等业务相关操作，是整个应用系统的核心。因此设计一个能够真实反映实际需要的业务层是非常必要的，我们将实际业务具体分为业务数据与业务操作两部分。</span><span lang="EN-US">&nbsp;</span></p>
<ul>
<li><span lang="EN-US"><span>业务数据</span> </span></li>
</ul>
<p><span><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>业务数据又是业务逻辑的核心，最终业务数据将以一种固定的格式表现于内存中，在系统的各个层次间传输，充当</span><span lang="EN-US">DTO</span><span>角色。表达业务数据的方式一般分为两种</span><span lang="EN-US">Table Model</span><span>和</span><span lang="EN-US">Domain Model</span><span>。</span></p>
<p><span lang="EN-US"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>Table Model</span><span>是将数据库中的表直接映射成为业务数据对象，这样的优点是适合于机器操作，</span><span lang="EN-US">ADO.NET</span><span>直接提供了这种操作的便利，但对于复杂业务关系的表达就很不直观。只适合于业务需求与数据表对应关系很直接的需要快速开发的情况。通常我们选用</span><span lang="EN-US">Dataset</span><span>或者强类型</span><span lang="EN-US">Dataset</span><span>（</span><span lang="EN-US">Strong Typed Dataset</span><span>），强类型</span><span lang="EN-US">Dataset</span><span>支持编译时的类型检查，效率上要略高于普通</span><span lang="EN-US">Dataset</span><span>。</span><span lang="EN-US">Dataset</span><span>有很多方便的特性：无需自己编写维护类，支持序列化，数据副本保存，支持数据集合，对控件绑定支持效果好，微软提供了相应的生成工具以及持久方案。但缺点也是明显，复杂数据表现不直观，做为</span><span lang="EN-US">DTO</span><span>在各个层次间传输，尤其是分布式环境，庞大的体积，相对缓慢的实例化对于性能造成很大压力。</span></p>
<p><span lang="EN-US"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>Domain Model</span><span>则是根据实际业务按照现实方式用</span><span lang="EN-US">OO</span><span>思想建模，这样很适合业务复杂的系统。通常采用自定义数据实体（</span><span lang="EN-US">Custom Data Entity</span><span>）方式表达。自定义数据实体，有着良好的性能，编译时的类型检查，数据表现方式非常直观符合实际业务的操作方式等优点，但需要自己定义维护类，在分布式环境下需要自己编写序列化方法。</span></p>
<p><span><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>综合各种因素考虑，虽然业务简单对应直接的系统我们以</span><span lang="EN-US">Table Model</span><span>建模开发效率很高但难免保证系统日后不会变的复杂，因此出于复用性，扩展性，性能等方面选用</span><span lang="EN-US">Domain Model</span><span>建模为佳。</span><span lang="EN-US">&nbsp;</span></p>
<ul>
<li><span lang="EN-US"><span>业务操作</span> </span></li>
</ul>
<p><span><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>业务操作负责对业务数据进行各种业务相关的处理，例如验证，流向，整合，事物，权限等，但它不负责有关对数据源的操作。它与业务数据的关系设计有</span><span lang="EN-US">2</span><span>种方式。</span></p>
<p><span><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>分离业务数据与业务操作，将业务数据单独封装到只有数据</span><span lang="EN-US">get</span><span>，</span><span lang="EN-US">set</span><span>的数据类中，这个数据类只充当</span><span lang="EN-US">DTO</span><span>。将业务操作封装到独立的</span><span lang="EN-US">service</span><span>类中与业务数据一起充当业务层。这样当系统不复杂的时候显的简单直观，而随着系统日益复杂，</span><span lang="EN-US">service</span><span>类会变的杂乱，而将本身耦合紧密的数据与操作分离对于复用也是不利的因素。具体可参考</span><span lang="EN-US">Martin Fowler </span><span>的</span><span lang="EN-US"><a href="http://martinfowler.com/bliki/AnemicDomainModel.html"><span><span lang="EN-US"><span style="color: #770000;"><span lang="EN-US">贫血的</span>Domain Model</span></span></span><span>一文。</span></a></span></p>
<p><span><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>整合业务数据与业务操作，将业务数据与相关的业务操作封装在一起称为业务实体，业务实体作为统一的业务层为表示层提供服务，同时也负责作为</span><span lang="EN-US">DTO</span><span>在各个层次间传输，我倾向于这样完整的</span><span lang="EN-US">Domain Model</span><span>设计方式，每个业务实体都可以做为一个单独组件形式存在，对于组件化复用有着莫大的好处。</span></p>
<p><span lang="EN-US">&nbsp;</span></p>
<h2><span>业务数据访问层</span></h2>
<p><span><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>业务数据访问层是一个针对具体应用系统的专属层，它为业务层提供与数据源交互的最小操作方式，仅仅是业务层需要的数据访问接口，业务层完全依赖业务数据访问层所提供的服务。这些服务负责从业务层接收数据或返回业务实体，它屏蔽了实际业务数据与机器存储方式的差别。当然，数据层选用抽象的解决方案同样可以达到这个效果，但业务数据访问层最大的特点就是针对具体业务做抽象，而抽象的数据层访问方案是针对通用做抽象。往往业务中针对具体的设计生命力会变的更强，这样我们可以最大限度的保持了上层代码的复用性，当需要更换存储策略如果数据层访问差别太大，通过更换数据层无法解决问题的时候我们最多只需要更换业务数据访问层，而无需改变业务层。</span><span lang="EN-US">&nbsp;</span></p>
<p><span><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>业务数据访问层由</span><span lang="EN-US">DAO</span><span>（</span><span lang="EN-US">Data Access Object</span><span>）层和系统服务层两部分组成。</span><span lang="EN-US">DAO</span><span>层为每个业务实体提供最基本的数据访问服务，系统服务层为系统全局提供与业务关系不大的通用数据访问服务，这两层处于系统中的同一个层次位置。</span></p>
<p><span lang="EN-US">&nbsp;</span></p>
<p align="center"><span>业务层与业务数据访问层关系图</span></p>
<p align="center"><span lang="EN-US">&nbsp;<img src="http://www.cnblogs.com/images/cnblogs_com/simonw/应用系统架构设计-业务层关系图.jpg" height="149" alt="" width="360" /></span></p>
<p align="center">&nbsp;</p>
<p align="center"><span lang="EN-US">&nbsp;</span></p>
<h2><span>数据层</span></h2>
<p><span><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>数据层的宗旨就是为数据源提供一个可供外界访问的接口，我们应该选用一种能够提供数据源无关的抽象数据访问接口并通过在其下挂接各种不同的</span><span lang="EN-US">DataProviador</span><span>来访问数据源的数据层组件，这样做便于移植到不同的数据源上。目前有以下</span><span lang="EN-US">3</span><span>种数据层方案：</span><span lang="EN-US">&nbsp;</span></p>
<p><span lang="EN-US"><span>1.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>封装</span><span lang="EN-US">ADO.Net</span></span></p>
<p><span><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>这些数据访问组件都是基于</span><span lang="EN-US">ADO.Net</span><span>的浅封装，它的优点在于封装层次低所以速度最快，我们可以手动组织</span><span lang="EN-US">sql</span><span>语句用来适应复杂的操作以及个性的优化等。缺点是无法直接处理自定义数据实体方式的业务实体对象，需要将业务实体中的数据属性以参数形式传入传出。这样的方式虽然最为保险，但随着系统规模增大，开发效率，质量，，后期的维护，二次开发都变成尤为突出的问题，对开发人员的要求会变的越来越高。另外对于事物操作封装不是很好，无法提供声明性事物，经常会在业务层出现访问数据层的需要。这样的组件目前应用的很广泛，例如微软在</span><span lang="EN-US"><a href="http://msdn.microsoft.com/library/en-us/dnpag2/html/entlib.asp"><span style="text-decoration: underline;"><span><span style="color: #770000;">EnterpriseLibrary</span></span></span></a></span><span>中提供的</span><span lang="EN-US">DAAB</span><span>（</span><span lang="EN-US">Data Access Application Block</span><span>），还有以前的</span><span lang="EN-US">DAAB3.1</span><span>。</span><span lang="EN-US">EnterpriseLibrary</span><span>是个成熟的产品，包括了数据访问，异常，日志，缓存，加密，配置</span><span lang="EN-US">,</span><span>安全等组件做为通用服务非常适合。</span><span lang="EN-US">&nbsp;</span></p>
<p><span lang="EN-US"><span>2.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span lang="EN-US">OR-Mapping</span><span>组件</span></span></p>
<p><span lang="EN-US"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>ORM</span><span>是最好的数据持久解决方案，它的优点在于能够以面向对象的方式操纵数据，因此可以直接处理自定义数据实体的业务对象，我们根本不用操心</span><span lang="EN-US">sql</span><span>语句以及底层存储方式，这样极大的简化的代码提高了开发效率，对于日后维护扩展都带来极大的便利。缺点在于屏蔽了底层使得我们无法针对具体数据源做优化，而且对于复杂关联的</span><span lang="EN-US">sql</span><span>操作有些力不从心，同时性能也差一些但辅助以缓存情况会好很多，而在</span><span lang="EN-US">dotNet</span><span>下最大的问题就是没有一个成熟便宜的</span><span lang="EN-US">ORM</span><span>产品供我们使用，全部都是</span><span lang="EN-US">beta</span><span>版本和商业版本。这些版本或多或少都存在一些问题，以至于真正应用中需要经过仔细考察。例如</span><span lang="EN-US">NHibernate</span><span>，</span><span lang="EN-US">Gentle.Net</span><span>，</span><span lang="EN-US">XPO</span><span>，</span><span lang="EN-US">Grove.Net</span><span>等等非常多。</span><span lang="EN-US">&nbsp;</span></p>
<p><span lang="EN-US"><span>3.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span lang="EN-US">DataMapper</span><span>（</span><span lang="EN-US">SqlMapper</span><span>）</span></span></p>
<p><span lang="EN-US"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>SqlMapper</span><span>为以上两种方式提供了一个折中的选择，它可以以面向对象的方式直接处理自定义数据实体的业务对象，同时可以根据与数据源与业务实体的映射关系执行手写的</span><span lang="EN-US">sql</span><span>语句，这样完全使得我们可以针对具体数据源做优化，对于复杂操作同样可以胜任。目前只有</span><span lang="EN-US"><a href="http://incubator.apache.org/ibatis/site/index.html"><span style="color: #770000;">iBatis.Net</span></a></span><span>一个产品，它是一个</span><span lang="EN-US">java</span><span>移至的开源项目，已经比较成熟，可以在无需编译的情况下随意替换</span><span lang="EN-US">DAO</span><span>。</span></p>
<p><span lang="EN-US">&nbsp;</span></p>
<h2><span>各层间的依赖关系</span></h2>
<p align="center"><span>依赖关系图：</span></p>
<p align="center">&nbsp;</p>
<p align="center"><span lang="EN-US"><img src="http://www.cnblogs.com/images/cnblogs_com/simonw/应用系统架构设计-依赖关系.jpg" height="444" align="center" alt="" width="377" />&nbsp;</span></p>
<p><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>在对各层的讨论之后，我们来总结一下各层间的依赖关系。说到依赖就离不开复用这个词，复用对软件开发流程的几乎每个阶段都有着重要的意义。在设计阶段它代表着更清晰的设计，在开发阶段它代表着更高的工作效率和代码质量，在测试阶段它代表着更轻易的捕获</span><span lang="EN-US">bug</span><span>，在维护和再开发阶段它代表着更小的工作量。更好的复用需要设计更好的依赖关系。</span><span lang="EN-US">&nbsp;</span></span></p>
<p><span><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>从图中可以看出表示层与业务数据访问层都依赖于业务层，而业务层是相对独立的，这样设计的优点就是最大限度的减少了变动对整个系统所带来的影响。最坏的情况就是业务的改变，业务改变其他依赖业务层的地方必须改变（在这里我们忽略了一些针对多种业务而设计的其他层组件，这些组件是可以适应有限的业务变更而本身不用变更的。），这个我们没有办法控制。但像表示层与业务数据访问层等其他非业务方面的改动不会影响到其他地方。</span><span lang="EN-US">&nbsp;</span></p>
<p><span><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>有人应该注意到了图中的配置文件。在没有它的时候，业务层是依赖于业务数据访问层的，细心的读者应该能从业务层与业务数据访问层关系图中发现这个问题。这样双向依赖的关系是以后造成无法复用的根本所在。因此需要抽象出业务数据访问接口，让业务层去依赖这个接口，而不是业务数据访问层。但光声明接口是不够的，因为在实例化的时候仍然需要具体的下层类，所以依旧无法摆脱依赖关系。于是把依赖转移出来，这又引出了依赖倒置（</span><span lang="EN-US">Dependency Inversion Principle</span><span>）的概念，具体可以参见</span><span lang="EN-US">Martin Fowler</span><span>的相关论述。</span><span lang="EN-US">IoC</span><span>（</span><span lang="EN-US">Inversion of Control</span><span>）容器为我们提供了完美的方案，通过它将不同的模块注入到系统中我们可以在不知道这个组件存在的情况下调用它。这样的方式同样适合于权限管理，邮件发送等等其他组件。</span><span lang="EN-US"><a href="http://www.springframework.net/"><span style="color: #770000;">Spring.Net</span></a></span><span>和</span><span lang="EN-US"><a href="http://www.castleproject.org/"><span style="color: #770000;">Castle</span></a></span><span>是</span><span lang="EN-US">dotNet</span><span>下的两个优秀的</span><span lang="EN-US">IoC</span><span>容器</span><span lang="EN-US">Spring.Net</span><span>是</span><span lang="EN-US">Java</span><span>下</span><span lang="EN-US">Spring</span><span>的移植版本，</span><span lang="EN-US">Castle</span><span>相对更要成熟。但是当你使用的组件并不是很多而不愿使用配置这些复杂而强大的产品时，你就要手工完成这些工作，你需要把业务层使用那些数据访问组件写在配置文件中，然后通过工厂（</span><span lang="EN-US">Factory</span><span>）解析配置文件应用反射（</span><span lang="EN-US">Reflection</span><span>）技术实例化出你的组件。</span><span lang="EN-US">&nbsp;</span></p>
<p><span><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>最后再说点关于</span><span lang="EN-US">AOP</span><span>（</span><span lang="EN-US">Aspect-OrientedProgramming</span><span>）的话题，在一些非常通用的组件或者系统功能间我们可以使用</span><span lang="EN-US">AOP</span><span>技术来打散系统其他部分对他们的依赖。像权限管理，系统日志，异常处理等。拿权限管理来举例，通常我们是在需要做权限检测的函数内部的开头来加一行权限检测代码，通过则执行后续代码否则跳出。这样写破坏了业务的纯洁性，业务的存在于权限并没有什么关系，而且使业务代码依赖权限组件，当我需要去除权限而另做新系统的时候这是见很麻烦的事情。</span><span lang="EN-US">AOP</span><span>的好处在于可以以声明方式来处理这些问题，例如你只需在需要验证的函数前加上一行属性的描述或者在配置文件中写上那些函数需要验证，执行时</span><span lang="EN-US">AOP</span><span>组件会按照你预先定制的先后顺序执行你的代码，这样我们可以轻松的剥离这些组件而丝毫不会对现有系统造成任何影响。</span></p>
<p><span lang="EN-US">&nbsp;</span></p>
<h2><span>关于</span><span lang="EN-US">Service</span><span>层的讨论</span></h2>
<p><span lang="EN-US"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>Service</span><span>层是一个构建于表示层于业务层之间的层，它是对业务层的一个浅封装而不应该封装过多的业务逻辑，否则会造成不必要的麻烦。然而它并不是任何时候都有必要存在。一种情况下当你的</span><span lang="EN-US">UI</span><span>所要展现的东西和你的业务实体并不是那么完全吻合的时候，例如你的界面需要显示若干个业务实体的一部分，但这并不是业务本身，只是一种展现方式。这时候你需要</span><span lang="EN-US">Service</span><span>层来做一个展现逻辑的转换。或者当你在做分布式系统的时候可以利用</span><span lang="EN-US">Service</span><span>层来实现一个粗粒度的服务接口。也可以以</span><span lang="EN-US">SOA</span><span>（</span><span lang="EN-US">Service-oriented Architecture</span><span>）的方式来理解</span><span lang="EN-US">Service</span><span>层，我们最终使用的是系统所提供的服务而不是业务对象，所以需要将将业务对象以清晰的方式组织起来形成清晰的服务暴露在外。更多的情况在于你结合实际该如何使用。</span></p>
<p><span lang="EN-US">&nbsp;</span></p>
<h2><span>结束语</span></h2>
<p><span><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>至此，整个架构方案的讨论已经完成，我们可以看出</span><span lang="EN-US">dotNet</span><span>下可供选择的解决方案是那么的有限，反看</span><span lang="EN-US">Java</span><span>世界，有那么多成熟可供利用的组件框架，甚是着急。不过</span><span lang="EN-US">dotNet</span><span>也正在走向成熟，我们需要时间等待。以上提供的方案仅代表了一种基本的思路，在具体环境中需要做具体的调整。希望能起到一个抛砖引玉的作用。我的<a href="http://www.cnblogs.com/images/cnblogs_com/simonw/mymail.GIF"><span style="color: #770000;">联系方式</span></a>见Blog</span><span>，由于经验不足，有不正确的地方欢迎指正讨论。</span><span lang="EN-US">&nbsp;</span><span lang="EN-US">&nbsp;</span></p>
          <br/>
          <span style="color:red;">
            <a href="http://isky.javaeye.com/blog/187525#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><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><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 28 Apr 2008 13:40:36 +0800</pubDate>
        <link>http://isky.javaeye.com/blog/187525</link>
        <guid>http://isky.javaeye.com/blog/187525</guid>
      </item>
      <item>
        <title>餐厅实用英语</title>
        <author>isky</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://isky.javaeye.com">isky</a>&nbsp;
          链接：<a href="http://isky.javaeye.com/blog/186634" style="color:red;">http://isky.javaeye.com/blog/186634</a>&nbsp;
          发表时间: 2008年04月25日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          This is a piece of work I can be proud of .这是我的得意之作<br />餐厅实用英语：<br />Could you recommend a nice restaurant near here？<br />是否可介绍一家附近口碑不错的餐厅？<br />Are there any inexpensive restaurants near here？<br />这附近是否有价位不贵的餐厅？<br />I'd like a quiet restaurant.我想去一家不会吵杂的餐厅<br />I'd like a restaurant with cheerful atmosphere.我想去一家气氛欢乐、活泼的餐厅。<br />Do you know of any restaurants open now？<br />你知道现在那里还有餐厅是营业的吗？<br />A：I'd like to have some local food.我想尝试一下当地食物。<br />B ：Could you recommend that kind of restaurant？<br />是否可建议这一类的餐厅？<br />Where is the main area for restaurants？<br />此地餐厅多集中在那一区？<br />餐厅预约：<br />Do I need a reservation？（昨天用到过，加深下印象）<br />我需要预约位子吗？<br />I'd like to reserve a table for three.我想要预约3个人的位子。<br />I'd like to reserve a table for two at seven tonight.我想要预约今晚7点2个人的位子。<br />what do you have for today's special？<br />今天的推荐餐是什么？<br />We are a group of six.我们共有6个人。<br />We'll come around eight o'clock.我们大约在8点到达。
          <br/>
          <span style="color:red;">
            <a href="http://isky.javaeye.com/blog/186634#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><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 25 Apr 2008 10:15:18 +0800</pubDate>
        <link>http://isky.javaeye.com/blog/186634</link>
        <guid>http://isky.javaeye.com/blog/186634</guid>
      </item>
      <item>
        <title>职场用语</title>
        <author>isky</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://isky.javaeye.com">isky</a>&nbsp;
          链接：<a href="http://isky.javaeye.com/blog/186632" style="color:red;">http://isky.javaeye.com/blog/186632</a>&nbsp;
          发表时间: 2008年04月25日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          don't slack off!别偷懒！slack[slack] 松弛，闲散。<br /><br />Do I have to make a reconfirmation? 我还要再确认吗？<br /> <br />Can I get a seat for todays 7:00 a.m. train? 我可以买到今天上午7点的火车座位吗？<br /> <br />Could you tell me my reservation number, please?请你告诉我我的预订号码好吗？<br /> <br />May I reconfirm my flight? 我可以确认我的班机吗？<br /><br />Can I reconfirm by phone?我能电话确认吗？<br /> <br />Are they all non-reserved seats? 他们全部不预订的吗？<br /><br />Where can I make a reservation? 我到哪里可以预订？<br /><br />May I see a timetable?我可以看时刻表吗？<br /><br />How long will I have to wait? 我要等多久呢？<br /><br />Do I need a reservation for the dining car? 我需要预订餐车吗？<br /><br />How many more minutes will it take for the train to arrive?火车还要多少分钟就要到达呢？<br />  <br />Excuse me. May I get by? 对不起，我可以上车吗？<br /><br />注：黄色部分为重要单词，此部分为职场用语
          <br/>
          <span style="color:red;">
            <a href="http://isky.javaeye.com/blog/186632#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/97' target='_blank'><span style="color:blue;font-weight:bold;">Oracle专区上线，有Oracle最新文章，重要下载及知识库等精彩内容，欢迎访问。</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</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>Fri, 25 Apr 2008 10:14:19 +0800</pubDate>
        <link>http://isky.javaeye.com/blog/186632</link>
        <guid>http://isky.javaeye.com/blog/186632</guid>
      </item>
      <item>
        <title>针对开发人员Microsoft Office SharePoint Server 2007工作流简介</title>
        <author>isky</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://isky.javaeye.com">isky</a>&nbsp;
          链接：<a href="http://isky.javaeye.com/blog/186303" style="color:red;">http://isky.javaeye.com/blog/186303</a>&nbsp;
          发表时间: 2008年04月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          针对开发人员的 Windows SharePoint Services V3 和 SharePoint Server 2007 <br /><br />适用于：<br /><br />Microsoft Windows SharePoint Services（版本 3）<br /><br />Microsoft Office SharePoint Server 2007<br /><br />摘要：关于 Microsoft Windows SharePoint Services（版本 3）如何实现 Windows Workflow Foundation 的工作流功能及 Microsoft Office SharePoint Server 2007 如何利用对称的 Microsoft Office InfoPath 2007 窗体来扩展这些功能的高级概述。 <br /><br />本页内容<br /> 工作流简介 <br /> 工作流体系结构 <br /> 工作流类型 <br /> 工作流组成 <br /> 工作流标记 <br /> Windows SharePoint Services 和 SharePoint Server 2007 中的工作流 <br /> 编写 SharePoint 工作流 <br /> 在 Visual Studio 2005 中编写 SharePoint 工作流 <br /> 在 SharePoint Designer 2007 中编写 SharePoint 工作流 <br /> 比较 Visual Studio 2005 Designer for Windows Workflow Foundation 和 SharePoint Designer 2007 <br /> Windows SharePoint Services 中的工作流结构 <br /> 使用工作流命名空间 <br /> 结论 <br /> 其他资源 <br /><br /><br />工作流简介<br />Microsoft Windows SharePoint Services 为用户提供稳健和可自定义的工作环境，以创建、协作和存储重要的业务信息。如今，利用 Microsoft Windows SharePoint Services（版本 3）和 Microsoft Office SharePoint Server 2007，可将自定义的业务进程附加于文档或列表项目。<br /><br />可以使用工作流来展现这些自定义业务流程。工作流是组织并运行一组工作单元或活动的自然方式，用来构成工作流程的可执行表示。该流程几乎可以控制 Windows SharePoint Services 中项目的任何方面，包括项目的生命周期。工作流的灵活性极佳，可以模仿完成工作流所必需的系统功能和人员操作。<br /><br />可以根据业务流程所需创建简单或复杂的工作流。可以创建用户启动的工作流，也可以创建 Windows SharePoint Services 根据某些事件（如创建或更改项目时）而自动启动的工作流。<br /><br />假定您需要创建一个简单的工作流，将文档发布给一系列用户进行批准或备注。该工作流将包含系统需要执行的操作并为用户提供与工作流按指定方式进行交互的界面。例如，在准备检查文档时 Windows SharePoint Services 将发送一封电子邮件消息给所选的用户。这些用户在完成检查之后必须可以通知 Windows SharePoint Services，或者输入一些备注。使用包含在 Windows SharePoint Services V3 中并在 SharePoint Server 2007 中得到扩展的工作流框架，您可以模仿如此复杂的工作流进程并将其以一种简单易懂且便于接受的方式呈现给终端用户，指导他们完成每一步流程。<br /><br />本文提供了工作流的高级概述，这些工作流在 Windows SharePoint Services 中得以实现并在 SharePoint Server 中得到扩展。本文讨论了开发人员在两种环境中创建工作流时可以使用的工具，以及这些工具各自的功能和优势所在。<br /><br /> 返回页首 <br /><br />工作流体系结构<br />在 Windows SharePoint Services V3 中的工作流功能构建于 Windows Workflow Foundation (WF) 之上，它是一种 Microsoft Windows 平台组件，为开发和执行基于工作流的应用程序提供编程基础结构和工具。WF 简化了异步编程的进程，以创建有状态、长时间运行及持久的工作流应用程序。WF 运行时引擎会管理工作流的执行，使工作流长时间保持活动状态，甚至在重新启动计算机时也不会受到影响。运行时服务提供了事务和持久性等功能，以适时而正确地管理错误。<br /><br />WF 运行时引擎提供每一工作流应用程序所需的服务，例如排序、状态管理、跟踪功能及事务支持等。WF 运行时引擎可用作状态机，负责加载和卸载工作流以及管理所运行的任何工作流的当前状态。WF 允许任何应用程序进程或服务容器通过托管 WF（即，在其进程内部加载 WF）来运行工作流。<br /><br />Windows SharePoint Services 托管 WF 运行时引擎。使用 WF 代替所包含的可插拔服务，Windows SharePoint Services 为引擎提供了以下服务的自定义实现：事务、持久性、通知、角色、跟踪和消息传送。然后，开发人员即可创建在 Windows SharePoint Services 内部运行的工作流解决方案。<br /><br />图 1 显示了 Windows SharePoint Services 中的工作流体系结构。Windows SharePoint Services 在其进程内部托管 WF 运行时引擎，并提供必要服务的自定义实现。WF 运行时引擎的功能以及 Windows SharePoint Services 提供的托管功能，通过 Windows SharePoint Services 对象模型得以实现。<br /><br /> <br /><br />图 1. Windows SharePoint Services V3 中的工作流体系结构 <br />Windows Workflow Foundation 还提供了 Visual Studio 2005 Designer for Windows Workflow Foundation，它是一种在 Microsoft Visual Studio 2005 开发系统内部托管的加载项，开发人员可用其创建自己的自定义工作流和工作流活动。有关详细信息，请参阅在 Visual Studio 2005 中编写 SharePoint 工作流。<br /><br />SharePoint Server 借用了 Windows SharePoint Services（版本 3）中的工作流功能，并通过与 InfoPath 窗体和其他工作流活动相集成而扩展了该功能。在 SharePoint Designer 2007 中编写 SharePoint 工作流对此做了更为详细的论述。<br /><br />Windows Workflow Foundation 运行时引擎作为 Microsoft Windows Workflow Foundation Runtime Components Beta 2.2 and Visual Studio 2005 Extensions for Windows Workflow Foundation Beta 2.2（英文）的一部分，可从 Microsoft 下载中心获得。此下载还包含 Visual Studio 2005 Designer for Windows Workflow Foundation 以及 Windows Workflow Foundation Software Development Kit (SDK)。<br /><br />既然已经对 Windows SharePoint Services 中所提供的工作流基础结构做了简短描述，接下来让我们开始研究 WF 工作流自身的内部组成和结构。之后，我们将要看看 Microsoft 为开发人员创建 Windows SharePoint Services 和 SharePoint Server 2007 的工作流解决方案所提供的各种工具。<br /><br />工作流持久性 <br /><br />Windows SharePoint Services 向 WF 工作流引擎所提供的一个最重要服务是持久性。包含人员交互的工作流必须可以长时间运行；即使在理想的环境下，与计算机相比人们也需要相对较长的时间才能完成工作。在许多 Microsoft Office 方案中，如果不是很长工作流，一般需要几天的时间。以发布供批准的文档的工作流为例。批准人可能需要几天的时间来检查文档。<br /><br />很明显，在其执行的整个持续时间内将每一个运行中的工作流均保留在内存中是不切实际的；不断累积的长时间运行工作流所需的资源很快就会使系统停止。<br /><br />因此，在工作流实例到达等待用户输入的时候，Windows SharePoint Services 会从内存中卸载该工作流实例而保留其数据。然后，在某一合适的事件（如用户输入数据）需要工作流实例再次启动时，Windows SharePoint Services 会使用所保留的数据重新创建工作流实例，因此工作流实例可根据需要接收和处理事件。<br /><br />尽管在某任意时刻可能有大量工作流实例在运行，但其中只有一小部分可能存在于内存中并使用系统资源。<br /><br /> 返回页首 <br /><br />工作流类型<br />Windows Workflow Foundation 支持两种基本的工作流类型：<br /><br />顺序工作流 将工作流显示为一系列按顺序执行的步骤，直到最后一个活动完成。不过，顺序工作流不会完全遵照它们的执行顺序。因为它们可以接收外部事件且包含并行逻辑流，因此活动执行的准确顺序可能会有所变化。 <br /><br />状态机工作流 显示一组状态、转换和操作。将某状态表示为开始状态，然后根据某一事件进行某种转换，使其成为另一种状态。状态机可具有确定工作流结束的最终状态。 <br /><br />可以为 Windows SharePoint Services 和 SharePoint Server 创建任一类型的工作流。<br /><br />顺序工作流 <br /><br />顺序工作流可以用图形的方式很好地表示为操作流程图：有开始、结束和从开始至结束的顺序流方向。顺序工作流可以合并诸如重复、循环和并行分支这样的流结构，但最终还是按照从开始操作至结束操作来前进的。<br /><br />例如，假定您要制定一张简单的工作流图表，该工作流在 Windows SharePoint Services 中分布供批准的文档。在工作流开始时，系统会通过电子邮件消息通知特定的检查人员有一个文档要进行检查。检查人员会检查该文档并通知系统任务已完成，无论该人员批准还是拒绝文档。根据检查人员的响应，工作流会执行两个并行分支中的一个。如果检查人员批准文档，则系统会将批准文档移动至一特定的 SharePoint 文档库，然后发送一条电子邮件消息给整个团队，通知他们此批准文档。如果检查人员拒绝此文档，则系统会通知文档作者。无论哪种情况，工作流都会到达其结尾并停止。图 2 显示了此工作流。<br /><br /> <br /><br />图 2. 顺序工作流的概念图表 <br />状态机工作流 <br /><br />与顺序工作流不同，状态机工作流没有预定的执行流，也不需要结束。相反，状态机工作流可定义项目可能具有的任意数量状态，还可定义将项目从一种状态转换至另一种状态的任意数量事件。<br /><br />图 3 显示了一个简单的文档发布进程，采用状态机工作流建模。创建文档时工作流启动，文档状态设置为完成时结束。不过，在这期间，文档不会按预定的路径进行，而是根据事件的发生在各状态间进行转换。<br /><br />状态机工作流由状态活动构成。每个状态活动表示一种项目的状态。每个状态活动均可包含可选的状态初始化、状态定案和一个或多个事件处理程序。每个事件处理程序活动可处理一个事件。在响应所处理的事件时，某进程处理可能完成，因此可转换到另一状态。<br /><br /> <br /><br />图 3. 状态机工作流的概念图表 <br />顺序工作流和状态机工作流的一个共同特点是每种类型的工作流均可以打断为离散操作（即，一部分操作由系统执行，一部分操作由用户执行）的集合。可以认为这些操作是工作流的构建块。在 WF 工作流中，这些操作称为活动。。<br /><br /> 返回页首 <br /><br />工作流组成<br />早期定义的工作流作为组织并运行一组工作单元或活动的方式用来构成工作流程的可执行表示。因此，每个 WF 工作流由一组相关活动构成。在 Windows Workflow Foundation 中，活动是建模、编程、重用和执行的基本单元。活动可由系统或用户来执行。例如，系统可以向某人发送电子邮件消息作为警告；或某人可以批准文档的分发。<br /><br />从概念上说，我们连续的工作流示例包括 5 个活动：<br /><br />发送电子邮件消息来通知批准人 <br /><br />批准或拒绝文档 <br /><br />将文档移动到“经批准的”文档库 <br /><br />发送电子邮件消息来通知团队 <br /><br />发送电子邮件消息来通知文档作者<br /><br />活动还可表示定义工作流范围并控制工作流的执行流的逻辑控制结构，与代码逻辑控制（如，If Then 和 Do While 循环）十分类似，能够控制代码中的程序流。<br /><br />活动可以具有属性、方法和事件。简单活动执行工作的单一单元，如“延时 1 天”或“调用 Web 服务”。复合活动包含其他活动；例如，带有两个分支的条件。还可以向活动附加处理程序，如，错误或补偿处理程序。特别建议将其用于复合活动。<br /><br />实际上，工作流本身就是一个复合活动，其包含了工作流中的所有其他活动。<br /><br />因此，可将工作流视为作为描述实际过程的模型存储的一组活动。工作从开始到结束遍历该模型，活动可由人或系统功能执行。工作流提供了一种方式来描述执行顺序以及多个短时运行工作或长时运行工作之间的依赖关系。<br /><br />Windows Workflow Foundation 包括若干预定义的活动，可用于您的工作流，您也可以创建自己的自定义活动。Windows SharePoint Services 工作流项目模板包包含了大量的活动，明确设计用于 Windows SharePoint Services 环境。此模板包还包含针对 Windows SharePoint Services 对象模型进行编程所必须的参考。类似地，对 SharePoint Server 项目模板包进行自定义，以用于 SharePoint Server 环境。有关详细信息，请参阅在 Visual Studio 2005 中编写 SharePoint 工作流。<br /><br /> 返回页首 <br /><br />工作流标记<br />每个 WF 工作流可由以下文件的组合来表示： <br /><br />包括工作流的声明性元数据的 XML 文件或标记文件 <br /><br />与包含表示工作流属性和行为的自定义代码的 code-behind 文件结合使用的标记文件 <br /><br />包括工作流的声明性逻辑和行为的代码文件<br /><br />标记文件以可扩展应用程序标记语言 (XAML) 编写而成，该语言具有文件必须遵守的已发布架构，且考虑到了 .xoml 文件扩展。<br /><br />因为 XAML 具有已发布的架构，所以可以选择使用任何文本编辑器或 XML 编辑器创建 XAML 文件。不过，本文章中所讨论的两个工作流编写工具 Visual Studio 2005 Designer for Windows Workflow Foundation 和 Microsoft Office SharePoint Designer 2007 为开发人员提供了图形界面，可在其中创建工作流并自动生成合适的标记文件。<br /><br />开发人员可以从工作流中包括的业务逻辑中选择集成或分离其声明性元数据。从概念上说，WF 工作流使用的“代码分离”模式与 Microsoft ASP.NET 中所使用的类似：声明性元数据与封装业务逻辑的文件分离。所以，尽管标记文件包含用于工作流中所包括的活动的元数据，这些活动的属性和行为仍在分离的文件中详细列出。<br /><br />对于使用代码分离编写的工作流，信息如之前所述仍保存在标记文件中，且以如下两种文件类型之一保存：<br /><br />包含封装业务逻辑的代码的 code-beside 文件。该文件可以 Microsoft Visual C# 或 Microsoft Visual Basic .NET 进行编写。 <br /><br />以声明性规则而非代码封装业务逻辑的工作流规则文件。<br /><br />以此方式创建的每个工作流实际是一个唯一的 Microsoft .NET 类型，构造于两个局部类，这两个类以 XOML 和 code-behind 或规则文件进行表示。对工作流项目进行编译后，这两个局部类被结合到 .NET 程序集中。以上即为通过使用 Visual Studio 2005 Designer for Windows Workflow Foundation 为 Windows SharePoint Services 或 SharePoint Server 编写工作流时所采用的方法。<br /><br />仅由代码文件组成的工作流遵守相同的常规编译过程，即，代码文件被编译到 .NET 类型中。<br /><br />此外，还可编译仅由标记文件组成的工作流。但这不是必要的；WF 运行时引擎可加载并运行未编译的标记工作流。以上即为通过使用 SharePoint Designer 2007 为 Windows SharePoint Services 或 SharePoint Server 编写工作流时所采用的方法。<br /><br /> 返回页首 <br /><br />Windows SharePoint Services 和 SharePoint Server 2007 中的工作流<br />迄今为止，我们已讨论了实现 Windows Workflow Foundation 的任何应用程序的工作流属性。现在，让我们深入研究专门在 Windows SharePoint Services 中实现的工作流并讨论该实现的某些重要方面。<br /><br />工作流模板和实例 <br /><br />在 Windows SharePoint Services 中，站点或列表上提供的工作流称为工作流模板；实际运行于特定 SharePoint 项目上的工作流称为工作流实例。所以，在给定的列表上，同一工作流模板的多个实例可以同时运行，每个实例运行在不同的 SharePoint 项目上。每次，可以有多个工作流运行在给定的 SharePoint 项目上。<br /><br />可以在文档或列表项上运行工作流。可以通过称为“关联”的过程使工作流模板在站点上可用，本文章稍后将进行讨论。<br /><br />使用窗体来启用用户与 Windows SharePoint Services 的交互 <br /><br />尽管可以使用 Windows SharePoint Services 工作流建模任意数量的唯一业务流程，但仍提供了多个公共阶段，其中用户可以与工作流模板或实例交互。<br /><br />为了使用户向工作流传递信息，开发人员必须通过使用窗体为此交互提供一个接口。向工作流添加窗体将使得工作流更加动态、灵活。窗体使您能够在工作流生命周期的预定义时间从用户收集信息，并使用户能够与针对该工作流的任务交互。<br /><br />从技术上说，可以将任何窗体技术用于 WF 工作流，只要窗体能够执行以下操作：<br /><br />调用 Windows SharePoint Services 对象模型 <br /><br />生成发送到 Windows SharePoint Services 对象模型所需的数据 <br /><br />接收并分析来自 Windows SharePoint Services 对象模型的所需数据<br /><br />任何在加载中传递给窗体的信息均转换为字符串，因为用户提交窗体时，窗体必须将该数据传递回 Windows SharePoint Services V3 对象模型。尽管该字符串通常为 XML，但仍可以使用任何可转换为字符串的数据格式，只要窗体能够生成该格式的字符串并分析其收到的字符串。<br /><br />Windows SharePoint Services 支持使用 ASP.NET 2.0 窗体。如何实现这些窗体将取决于开发人员所使用的工作流编写工具，即 Visual Studio 2005 Designer for Windows Workflow Foundation 或 SharePoint Designer 2007。此外，SharePoint Server 2007 使得开发人员能够将 Microsoft Office InfoPath 窗体与其工作流进行集成。这些 InfoPath 窗体可以在 Microsoft Office 客户端应用程序（例如 Microsoft Office Word、Microsoft Office PowerPoint、Microsoft Office Excel 和 InfoPath）以及客户端浏览器内进行托管，并提供了更丰富的客户端体验。有关每个工作流编写工具如何实现工作流窗体的详细信息，请参阅 Windows SharePoint Services 工作流中的 ASP.NET 窗体、SharePoint Server 工作流中的 InfoPath 窗体和 SharePoint Designer 工作流中的 ASP.NET 窗体。<br /><br />无论使用何种窗体技术，每个窗体的概念操作均相同。Windows SharePoint Services 在工作流的合适结合点向用户显示窗体。用户输入信息并提交窗体。<br /><br />作为工作流开发人员，您有责任对用户提交窗体后将发生的情况进行编程处理。多数情况下，窗体会调用 Windows SharePoint Services 对象模型并调用合适的方法来向正确的工作流实例传递窗体信息。<br /><br />如果对窗体和工作流活动进行编程以分析该字符串，信息字符串可以是任何格式。多数情况下，开发人员可能会选择使用 XML。<br /><br />Windows SharePoint Services 将字符串信息传递给 WF 运行时引擎、工作流实例，最终传递给工作流实例内的正确活动。活动接收到信息后会按编程预定的方式响应。图 4 显示了窗体集成工作流的方式。<br /><br /> <br /><br />图 4. 窗体集成工作流 <br />Windows SharePoint Services 工作流中使用了如下三种类型的窗体：<br /><br />关联和初始化窗体 关联和初始化窗体为用户在任何工作流实际启动之前进行填充而显示。通过这些窗体用户可以在工作流启动前设置工作流的参数和其他信息。 <br /><br />修改窗体 修改窗体为提供给用户的可选项，以在工作流运行在某项目上时对其进行更改。随后可以创建修改窗体使用户能够指定修改的参数。 <br /><br />任务窗体 基于工作流任务类型，还可以在您的工作流中为任务指定自定义窗体。Windows SharePoint Services 中的每个工作流任务类型均分配了一个内容类型；内容类型定义确定了是否为给定的工作流任务类型指定自定义窗体。<br /><br />上述三种类型的窗体表示预定义阶段，其中用户可以与工作流进行交互。接下来我们将讨论这些阶段。<br /><br />用户与工作流交互的要点 <br /><br />让我们深入研究一下各个阶段，其中用户可以与 Windows SharePoint Services 和 SharePoint Server 中的工作流进行交互。<br /><br />关联 <br /><br />站点管理员在特定文档库、列表或内容类型上提供了工作流模板时将发生关联。在此阶段，站点管理员为特定文档库、列表或内容类型自定义工作流，方法为指定以下参数信息：<br /><br />工作流的唯一名称 <br /><br />工作流应用于给定项目的方式：创建或更改项目时为自动，或为手动；可启动工作流的角色，如管理员或参与者 <br /><br />工作流在其中创建任务的任务列表 <br /><br />工作流在其中存储由工作流定义的历史事件的历史列表<br /><br />此外，工作流开发人员使得网站管理员能够通过设置针对特定工作流的参数信息来进一步自定义工作流。该管理员可能需要为工作流指定参数、默认值及其他信息，以便工作流适用于管理员将其关联的列表、库或内容类型上的项目。<br /><br />关联工作流实际发生在工作流自身的外部；关联期间实际上没有启动任何工作流实例。而是，Windows SharePoint Services 将关联信息存储在专门的内部工作流关联表格中。然后，在工作流实例实际启动时，Windows SharePoint Services 使用关联数据（以及初始化数据，如果有）来设置新工作流实例的参数。<br /><br />初始化 <br /><br />关联处理适用于特定列表、库或内容类型的工作流，而初始化处理适用于特定 SharePoint 项目的工作流。<br /><br />用户在特定项目上实际启动工作流实例后，发生初始化。必要时，用户提供该项目上的特定工作流的自定义信息，然后启动工作流。<br /><br />工作流开发人员可使用初始化使得用户可以覆盖或附加管理员设置的关联参数，或指定其他有关适用于给定的 SharePoint 项目的工作流的参数或信息。并非所有工作流均需要初始化。实际上，设置为自动启动的工作流不能包含初始化参数。<br /><br />用于 Visual Studio 2005 Designer for Windows Workflow Foundation 的 Windows SharePoint Services 工作流项目包括一个活动，该活动作为初始化工作流时的事件处理程序。该活动是任何 Windows SharePoint Services 工作流中的首个活动。<br /><br />修改 <br /><br />修改使得用户可以改变正在运行的工作流实例的参数或流程。作为开发人员，您可以在工作流中设置多个点，通过它们使得用户可以在工作流运行在项目上时，对其进行修改。例如，您可能希望使得用户可以为其他人分配任务，或者甚至可以向工作流添加特定任务。为用户提供的以在工作流运行在某项目上时对其进行更改的选项称为修改。<br /><br />用于 Visual Studio 2005 Designer for Windows Workflow Foundation 的 Windows SharePoint Services 工作流项目包括一个启用工作流修改的活动，以及一个启用工作流修改时作为事件处理程序的活动。<br /><br />任务 <br /><br />由用户所执行的工作流活动表示为 Windows SharePoint Services 工作流中的任务。<br /><br />作为工作流作者，您可以指定任务架构。例如，任务列表可包括以下各项：<br /><br />任务标题 <br /><br />任务分配到的用户的名称 <br /><br />任务状态 <br /><br />任务优先级 <br /><br />任务截止日期 <br /><br />到引用项目的链接<br /><br />随后用户可以根据需要编辑任务。工作流实例会收到工作流任务更改的通知并可以按工作流中指定的方式选择对其进行响应。<br /><br />用于 Visual Studio 2005 Designer for Windows Workflow Foundation 的 Windows SharePoint Services 工作流项目包括创建、删除及更新任务的活动，以及创建、更新或删除任务时作为事件处理程序的活动。<br /><br /> 返回页首 <br /><br />编写 SharePoint 工作流<br />Microsoft 为 Windows SharePoint Services 提供了两种用于编写工作流的开发工具：Visual Studio 2005 Designer for Windows Workflow Foundation 和 Office SharePoint Designer 2007。由于每种编写工具所生成的工作流分别具有不同的属性和功能，因此需要仔细检查每种工具。<br /><br />图 5 显示了使用每种编写工具创建、部署、关联和运行工作流时需要执行的不同步骤。通常，这两种工具之间的最大差别在于：<br /><br />Visual Studio 2005 Designer for Windows Workflow Foundation 中的工作流编写由专业开发人员执行，由其创建可跨多个站点部署并含有自定义代码和活动的工作流模板。开发人员然后将该工作流模板传给服务器管理员进行实际部署和关联。 <br /><br />SharePoint Designer 中的工作流编写适于某些非专业的开发人员来完成，如，想要为特定列表或文档库创建工作流的 Web 设计者或知识工作者。此时，设计者将局限于安全控件列表上的工作流活动，同时该工作流不能包括自定义代码。在工作流编写过程中，工作流编写者会将工作流模板直接部署到列表或文档库中。<br /><br />有关这两个工具功能的详细比较，请参阅比较 Visual Studio 2005 Designer for Windows Workflow Foundation 和 SharePoint Designer 2007。<br /><br /> <br /><br />图 5. 工作流编写、部署和初始化进程 <br /> 返回页首 <br /><br />在 Visual Studio 2005 中编写 SharePoint 工作流<br />Visual Studio 2005 Designer for Windows Workflow Foundation 是 Visual Studio 2005 的一个加载项，它提供了通过使用图形界面来快速开发工作流的方法，其中利用了开发人员关于 Visual Studio 开发环境的知识。<br /><br />Visual Studio 2005 Designer for Windows Workflow Foundation 是一个可供您按照与用于封装业务流程的代码开发相集成的方式来快速创建工作流的工具。为此，Visual Studio 2005 Designer for Windows Workflow Foundation 提供了一个包含直观控件的图形界面，该界面托管于常用的 Visual Studio 开发环境中。其功能包括：<br /><br />一个拖放式画面，允许通过您从“Toolbox”（工具箱）中拖出的预定义工作流活动集合自定义工作流 <br /><br />允许您使用直观图形工具来处理工作流标记的界面 <br /><br />与“Properties”（属性）窗口集成，因此开发人员可通过图形界面或直接在 code-beside 文件中配置工作流活动的属性，并使得这两者始终保持同步 <br /><br />通过附加到 Windows SharePoint Services 进程调试您的工作流，包括在工作流中设置断点 <br /><br />能够为活动附加错误、补偿和事件处理程序，并能够以图形方式“注释掉”活动<br /><br />Microsoft 下载中心的 Microsoft Windows Workflow Foundation Runtime Components Beta 2.2 and Visual Studio 2005 Extensions for Windows Workflow Foundation Beta 2.2（英文）中提供了 Visual Studio 2005 Designer for Windows Workflow Foundation。此下载中还包含 Windows Workflow Foundation 运行时引擎以及 Windows Workflow Foundation SDK。<br /><br />为进一步协助您的工作流开发，Microsoft 还提供了两个 Visual Studio 项目模板包，以与 Visual Studio 2005 Designer for Windows Workflow Foundation 一同使用：一个是针对 Windows SharePoint Services 工作流而定制，另一个是针对为 SharePoint Server 创建工作流而定制。<br /><br />Windows SharePoint Services 工作流项目模板含有对 Windows SharePoint 命名空间的引用，并包括专门针对 Windows SharePoint Services 环境而设计的自定义工作流活动。通过这些自定义活动，您能够执行 Windows SharePoint Services 环境的一些常用功能，如创建、更新、完成和删除 SharePoint 任务以及发送电子邮件和启用工作流修改。<br /><br />SharePoint Server 工作流项目含有 Windows SharePoint Services 工作流项目模板中的一切内容，以及对 SharePoint Server 命名空间的引用和其他用于在 SharePoint Server 工作环境中管理工作流任务的功能。<br /><br />Visual Studio 中的工作流开发过程 <br /><br />通常，在使用 Visual Studio 2005 Designer for Windows Workflow Foundation 为 Windows SharePoint Services 或 Office SharePoint Server 开发工作流时，需执行以下基本步骤：<br /><br />在 Visual Studio 2005 Designer for Windows Workflow Foundation 中编写工作流，包括 code-beside 文件（如果需要）。 <br /><br />设计并发布要与工作流一同使用的任何窗体。 <br /><br />编写功能定义和工作流模板定义文件，其中包含工作流程序集的相关信息，并将窗体绑定到工作流程序集。 <br /><br />将工作流文件编译为 .NET 程序集。 <br /><br />将工作流程序集和工作流定义打包在一起，并使用 Windows SharePoint Services 中的功能对其进行部署。 <br /><br />使用 Visual Studio 2005 Designer for Windows Workflow Foundation 调试活动的工作流程序集。 <br /><br />根据需要重新编译和部署工作流程序集以修复发现的所有错误。<br /><br />以下部分概述了其中的每一个开发步骤。<br /><br />使用 Visual Studio 2005 Designer for Windows Workflow Foundation 创建工作流 <br /><br />选择新的 Windows SharePoint Services 或 Office SharePoint Server 工作流项目时，Visual Studio 将显示 Visual Studio 2005 Designer for Windows Workflow Foundation 设计画面（图 6）。此设计画面提供了一个图形界面，在其中可通过从“Toolbox”（工具箱）中拖放各种活动来集合工作流。<br /><br /> <br /><br />图 6. Visual Studio 2005 Designer for Windows Workflow Foundation 界面 <br />在将某个特定活动拖到工作流上时，Visual Studio 2005 Designer for Windows Workflow Foundation 将向您显示该活动在此工作流中的有效位置。您不能将活动放置在对于它无效的位置中。例如，不能将 Send 活动作为 Listen 活动分支中的第一个活动来放置。如图 7 中所示，Visual Studio 2005 Designer for Windows Workflow Foundation 通过显示绿色的加号图标来指示特定活动的有效位置。<br /><br /> <br /><br />图 7. 工作流活动的有效位置 <br />在以图形方式设计工作流时，Visual Studio 2005 Designer for Windows Workflow Foundation 实际上会生成对应的标记。<br /><br />此外，如果要使用代码分离，工作流项目中会包含一个 code-behind 文件，可在其中编写工作流的业务逻辑。需要时，可在工作流设计画面和 code-beside 文件之间进行操作切换。<br /><br />设置工作流属性 <br /><br />向工作流添加活动后，只有为该活动设置属性，其才会在工作流中有效。可使用标准的 Visual Studio“Properties”（属性）窗口来设置这些属性。可指定的数据类型取决于属性自身所接受的数据类型：文字值、变量或方法名。<br /><br />如果要为属性指定变量，可使用两种方法：一种是在“Properties”（属性）窗口中输入变量名，此种情况下，Visual Studio 2005 Designer for Windows Workflow Foundation 会在 code-behind 文件中自动声明该变量；另外一种是在 code-behind 文件中声明变量，然后在“Properties”（属性）窗口中将其选中。<br /><br />有些活动属性实质上是对符合特定签名的 code-beside 文件中方法的引用。与变量名一样，您可在“Properties”（属性）窗口中输入方法名，然后让 Visual Studio 2005 Designer for Windows Workflow Foundation 将方法签名添加到 code-behind 文件中，或者，可在 code-behind 文件中创建方法，然后在“Properties”（属性）窗口中将其选中。<br /><br />还可将某个属性绑定到其他活动的属性。<br /><br />处理程序活动 <br /><br />工作流可能具有多个潜在的故障点。跟踪工作流的状态并在发生错误时进行报告是很重要的，这样便能够准确地解决问题，且花费的代价最少。就工作流而言，保持一组密切相关的操作的完整性同等重要，这样，在某个操作的一部分发生而另一部分却没有时，可将整个操作回滚。可使用 FaultHandlerActivity、TransactionScopeActivity、CompensationHandlerActivity 和 CancellationHandlersActivity 活动处理错误以维护工作流的状态，并在问题发生时加以修复。<br /><br />您可将 FaultHandlersActivity 活动视为 C 语言的 try 块，并可向其附加相当于异常处理程序的 FaultHandlerActivity 活动的有序集合。可将这些异常处理程序视为 C 语言的 catch 块。如果在执行复合活动期间引发异常，则 WF 运行时引擎会将此异常与 FaultHandlerActivity 活动所处理的异常类型进行匹配。如果运行时引擎未发现匹配的异常处理程序，则将此异常传递到下一更高级别的复合活动，在其中重复此过程，以此类推，直至找到相应的处理程序。<br /><br />您也可拥有用于响应事件的 EventHandlersActivity 活动，方法是向 EventHandlerScopeActivity 活动添加事件处理程序。从概念上讲，这些事件处理程序与 C 或 Visual Basic .NET 语言中的处理程序非常相似。要创建事件处理程序，必须使用 EventDrivenActivity 活动。<br /><br />CompensationHandlerActivity 活动含有用于补偿或回滚复合活动的操作的代码（如果该活动未成功执行）。<br /><br />Windows SharePoint Services 工作流中的 ASP.NET 窗体 <br /><br />如前文所述，您可以使用 ASP.NET 来创建要与 Windows SharePoint Services 工作流一起使用的窗体。随后，在工作流的适当阶段，这些窗体会显示在 Windows SharePoint Services 用户界面中。<br /><br />通过您在工作流模板定义 XML 文件中所提供的信息，工作流窗体会被后期绑定到工作流程序集中。工作流模板定义架构包含一些元素，它们用于指示可与 Windows SharePoint Services 工作流一起使用的各种窗体的 URL。因此，可为用于任何自定义工作流修改的窗体以及用于工作流中所使用的各种 SharePoint 任务的窗体创建元素。<br /><br />多数情况下，工作流程序集自身不包含任何与工作流窗体本身相关的信息。开发人员只需编辑工作流定义 XML（而不必一定重新编译工作流程序集本身）便可更改要使用的工作流窗体。工作流修改是一个例外；实现工作流修改的每个活动必须包含用于该工作流修改的窗体的 GUID。<br /><br />SharePoint Server 工作流中的 InfoPath 窗体 <br /><br />尽管也可以在 SharePoint Server 工作流中使用 ASP.NET 工作流窗体，但 SharePoint Server 能够让您扩展工作流窗体并在 Microsoft Office 客户端应用程序中显示这些窗体。<br /><br />可将 InfoPath 窗体与工作流一起使用。可通过 InfoPath 创建对称窗体，即，无论这些窗体是显示在 SharePoint Server Web 界面中还是显示在 Microsoft Office 客户端应用程序（如 Word、Excel 或 PowerPoint）中，它们的外观和操作均完全相同。这就提供了更加丰富的交互体验，用户可直接在客户端应用程序中与工作流交互，而不必离开客户端并切换到 SharePoint Server Web 界面。而且作为开发人员，您不必创建两个独立的窗体（一个用在服务器上，另一个用在客户端中）来为用户提供客户端应用程序集成。<br /><br />有关创建常见对称窗体的详细信息，请参阅 Microsoft Office InfoPath 2007 客户帮助或 Office Online。<br /><br />Office Forms Services 是适用于 InfoPath 窗体的基于服务器的运行时环境，SharePoint Server 使用它来托管工作流窗体。Office Forms Services 使用您在 InfoPath 客户端应用程序中所创建的窗体，并将这些窗体显示在 ASP.NET 框架中，ASP.NET 框架相当于窗体的运行时环境。此环境提供与 InfoPath 客户端应用程序相匹配的窗体编辑体验。<br /><br />有关 Office Forms Services 的详细信息，请参阅 Microsoft Office SharePoint Server 2007 SDK。<br /><br />注意 由于 Office 2007 客户端应用程序（如 Word、PowerPoint 和 Excel）具有托管 InfoPath 窗体的功能，因此用户不必安装 InfoPath 客户端应用程序来利用其丰富的集成。<br /><br />显示 InfoPath 工作流窗体 <br /><br />SharePoint Server 使用相同的基本技术来显示所有自定义 InfoPath 工作流窗体，包括关联、初始化、修改或编辑任务窗体。<br /><br />当用户在 SharePoint Server 界面中单击链接来显示某个工作流窗体时，SharePoint Server 会加载一个 ASPX 页面，其中包含 Office Forms Services Web 部件。此 Web 部件随后会将相应的 InfoPath 窗体转换成 ASP.NET 并将其加载。当用户提交该窗体时，Web 部件会收到窗体中的数据并相应地对其进行处理。<br /><br />SharePoint Server 中包括其中包含 Office Forms Services Web 部件的 ASPX 页面。<br /><br />指定 InfoPath 工作流窗体 <br /><br />此外，在工作流模板定义（而非工作流自身）中指定您要使用的自定义窗体。多数情况下，这涉及到设置两个元素。首先，将该工作流进程（关联、初始化、修改等）的窗体 URL 设置为 SharePoint Server 中包含的适当的 ASPX 托管页面。接下来，添加一个元素，用来为该类型工作流进程指定自定义 InfoPath 窗体的 URN。<br /><br />通过使用 InfoPath 工作流窗体提交信息 <br /><br />为了使托管 ASPX 页面接收到被托管窗体中的数据，开发人员在 InfoPath 窗体中添加了一个“Submit”（提交）按钮。通过借助到托管环境的数据连接，此按钮使用某个规则来提交数据。当用户单击“Submit”（提交）按钮时，此连接会自动将数据传递回托管 ASPX 页面中。随后，托管 ASPX 页面会对数据分析进行处理，并根据需要将其传递回工作流或文档库。<br /><br />部署工作流 <br /><br />完成对工作流的指定后，您可以选择将工作流作为工作流或是作为活动来进行编译。<br /><br />完成对工作流的编译后，您可使用 SharePoint Features 功能来打包和部署工作流程序集以及任何必需的支持文件。<br /><br />功能打包是一种为了便于部署而封装 Windows SharePoint Services 解决方案和功能的方式。开发人员可根据它所提供的机制来打包解决方案（如工作流、Web 部件、列表和站点定义）所需的文件，以便于分布和部署。开发人员将所需文件打包为 .wsp 文件，该文件实质上是一个 .cab 文件，其中包含列有所含内容的清单。有关 SharePoint Features 的详细信息，请参阅 Windows SharePoint Services V3 SDK。<br /><br />您部署的每个工作流模板必须包含一个工作流模板定义文件。工作流模板定义是一个 XML 文件，它包含 Windows SharePoint Services 实例化和运行工作流时所需的信息，诸如以下内容：<br /><br />工作流模板的名称、GUID 及描述 <br /><br />程序集 <br /><br />与此工作流模板一起使用的任何自定义窗体的 URL（或 IP 窗体的 URN） <br /><br />工作流名称、工作流引擎名称以及运行工作流时要使用的托管服务程序集的名称（可选） <br /><br />这些程序集中要调用的正确的类（可选）<br /><br />必须将工作流程序集本身部署到全局程序集缓存中。<br /><br />在将其部署到站点后，该工作流即可作为工作流模板使用，SharePoint 管理员可将其与该站点上的文档库和列表相关联。<br /><br />调试工作流 <br /><br />部署工作流程序集后，可通过打开工作流项目并附加到 Windows SharePoint Service w3wp 进程来调试工作流。<br /><br />由于 Visual Studio 2005 Designer for Windows Workflow Foundation 是在 Visual Studio 中进行托管的，因此可充分利用 Visual Studio 的调试功能。对于 code-beside 文件中所编写的代码以及设计画面中的工作流活动，均可设置断点。<br /><br />注意 为方便调试，强烈建议您在计划部署工作流模板的服务器上开发这些工作流模板。<br /><br />Visual Studio 2005 Designer for Windows Workflow Foundation 不仅支持标准的 Visual Studio 调试功能（如“Breakpoints”（断点）和“Call Stack”（调用堆栈）窗口），它还包含一系列可视指示器，用于在调试过程中提供信息。在调试程序集的同时，还可向工作流活动添加断点。<br /><br />可执行“步入”、“步出”和“单步跳过”操作来运行整个工作流代码。<br /><br />Visual Studio 2005 Designer for Windows Workflow Foundation 不支持下列调试类型：<br /><br />托管进程中运行时异常的实时调试 <br /><br />通过在“Task Manager”（任务管理器）中选择进程进行实时调试<br /><br />有关使用 Visual Studio 2005 Designer for Windows Workflow Foundation 进行调试的详细信息，请参阅 Windows Workflow Foundation SDK。<br /><br />注意 在 Microsoft 下载中心的 Microsoft Windows Workflow Foundation Runtime Components Beta 2.2 and Visual Studio 2005 Extensions for Windows Workflow Foundation Beta 2.2（英文）下载中提供了 Windows Workflow Foundation SDK。此下载中还包含 Visual Studio 2005 Designer for Windows Workflow Foundation 以及 Windows Workflow Foundation 运行时引擎。<br /><br /> 返回页首 <br /><br />在 SharePoint Designer 2007 中编写 SharePoint 工作流<br />在 Office SharePoint Designer 2007 中编写工作流时，您是直接针对 Windows SharePoint Services 中的特定列表或文档库来编写该工作流和进行数据绑定。您使用的是预定义的工作流活动列表，并不使用任何代码。您设计的工作流将不作为程序集进行编译，而是作为源文件进行存储，直到在它首次运行时，Windows SharePoint Services 才会对它进行编译。<br /><br />该方法具有以下优点：<br /><br />可快速开发和测试工作流。 <br /><br />由于工作流特定于给定列表，因此部署过程相对简单一些。 <br /><br />因为同样的原因，安全问题也简单了许多。 <br /><br />由于并未将工作流编译为程序集，因此，可将 SharePoint Designer 中所创建的工作流部署到服务器上（其中，管理策略禁止自定义代码程序集）。<br /><br />注意 SharePoint Designer 中所编写的工作流收集自预定义活动的“安全列表”，管理员可能已批准这些活动在服务器上运行。<br /><br />工作流可由具有较少开发人员经验的用户创建，如 Web 设计者或知识工作者。<br /><br />这种方法还表明，SharePoint Designer 中编写的工作流与使用 Visual Studio 2005 Designer for Windows Workflow Foundation 创建的工作流在一些重要的方面存在着差异：<br /><br />在 SharePoint Designer 中编写的工作流不能被部署到多个列表中。工作流仅对专门为之创建该工作流的列表有效。 <br /><br />由于直接对列表编写工作流，所以该工作流在设计时与该列表相关联。因此，在 SharePoint Designer 中编写的工作流不包含关联阶段。 <br /><br />对于在 SharePoint Designer 中编写的工作流，不能执行工作流修改。 <br /><br />不能对 SharePoint Designer 中的内容类型进行编写。<br /><br />有关详细的比较信息，请参阅比较 Visual Studio 2005 Designer for Windows Workflow Foundation 和 SharePoint Designer 2007。<br /><br />运行 SharePoint Designer 2007 中所编写的工作流 <br /><br />由于在 Office SharePoint Designer 中编写的工作流不包含自定义代码，因此它们不作为程序集进行编译和部署。而是作为各自的源文件存储在 Windows SharePoint Services 内部，并仅当需要时才被编译到内存中。<br /><br />对于每个站点，这种类型的工作流均存储在单独的文档库中。对于在 SharePoint Designer 中编写的每个工作流，此文档库均包含一个文件夹。此文件夹包含该工作流所需的所有源文件，其中包括：<br /><br />工作流标记文件 <br /><br />工作流规则文件 <br /><br />任何自定义工作流窗体所需的 ASPX 窗体<br /><br />Windows SharePoint Services 包括一个实时编译器，用来在工作流首次在某个项目上启动时将源文件编译成工作流。Windows SharePoint Services 将已编译的工作流保留在内存中，直到它再次被调用，这类似于服