<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>fangzhouxing</title>
    <description></description>
    <link>http://fangzhouxing.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>Python/Django学习笔记(3)：用一周时间学习Python语言</title>
        <author>fangzhouxing</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fangzhouxing.javaeye.com">fangzhouxing</a>&nbsp;
          链接：<a href="http://fangzhouxing.javaeye.com/blog/199812" style="color:red;">http://fangzhouxing.javaeye.com/blog/199812</a>&nbsp;
          发表时间: 2008年06月03日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用了一周时间学习Python语言，把《Learning Python(第3版,2007.10)》这本书的内容基本上比较仔细地看了一遍。本文摘录一些有趣的语言特性。</p>
<p>&nbsp;</p>
<p><strong>1. ==和is操作符</strong>
</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; 来自: 第4章：Introducing Python Object Types</p>
<p>&nbsp;&nbsp;&nbsp; 例子1：</p>
<pre name="code" class="python">	L = [1, 2, 3]
	M = [1, 2, 3]
	L == M  &lt;-- true
	L is M  &lt;-- false
</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 例子2：</p>
<pre name="code" class="python">L = [1, 2, 3]
M = L                # M and L reference the same object
L == M    &lt;-- 分别指向的对象是否相同？true
L is M  &lt;-- 是否指向同一个对象？true
</pre>
&nbsp;
<p><strong>2. 字符串加前缀字母</strong>
</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; 来自: 第4章：Introducing Python Object Types</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 例子1：</p>
<pre name="code" class="python">	myfile = open(r'C:\new\text.dat', 'w')
	 相当于：
        myfile = open('C:\\new\\text.dat', 'w')
</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 例子2：u表示中文字符</p>
<p>&nbsp;</p>
<pre name="code" class="python">#coding=utf-8

menuDefinitions = [{
        &quot;title&quot; : u'编程示范',
        &quot;cls&quot; : 'active',
    。。。
</pre>
<p>&nbsp;</p>
<p><strong>3.slicing(片段)的概念&nbsp;</strong>
</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 来自: 第4章：Introducing Python Object Types</p>
<pre name="code" class="python">	str = &quot;media/client/menuitem/Namespace.js&quot;
	str[-12:]==&quot;Namespace.js&quot;
	str[:-12]==&quot;media/client/menuitem/&quot;
</pre>
&nbsp;
<p><strong>4.通过例子学习List Comprehensions</strong>
</p>
<p>&nbsp;&nbsp;&nbsp; 来自：第4章：Introducing Python Object Types</p>
<pre name="code" class="python">squares = [x ** 2 for x in [1, 2, 3, 4, 5]]  &lt;------ List Comprehensions

与下面的for等价：
squares = []
for x in [1, 2, 3, 4, 5]:
    squares.append(x ** 2)</pre>
<p>&nbsp;</p>
<p><strong>5.用缩进来标识代码块</strong>
</p>
<p>&nbsp;&nbsp;&nbsp;  来自：第10章：Introducing Python Statements</p>
<p>&nbsp;&nbsp;&nbsp; 这是最令人吃惊的语言特性！</p>
<pre name="code" class="python">格式:
    Header line:
        Nested statement block  
</pre>
<p>&nbsp;</p>
<p><strong>6.只要用一条语句就能交换两个变量的值</strong>
</p>
<p>&nbsp;&nbsp;&nbsp; 来自：第11章 Assignment, Expressions, and print</p>
<pre name="code" class="python">nudge = 1
wink = 2
nudge, wink = wink, nudge   &lt;----- Tuple assignment
</pre>
<p>&nbsp;</p>
<p><strong>7.If 测试</strong>
</p>
<p>&nbsp;&nbsp;&nbsp; 来自：第12章 if Tests</p>
<p>&nbsp;&nbsp;&nbsp; 例子1：</p>
<pre name="code" class="python">branch = {'spam': 1.25,
      'ham': 1.99,
      'eggs': 0.99}

print branch.get('spam', 'Bad choice') &lt;--- 代替了if
</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 例子2：</p>
<pre name="code" class="python">   -- A = Y if X else Z
      也可以写为: A = [Z, Y][bool(X)]
</pre>
<p>&nbsp;</p>
<p><strong>8. 循环</strong>
</p>
<p>&nbsp;&nbsp;&nbsp; 来自：第13章 while and for Loops</p>
<p>&nbsp;&nbsp;&nbsp; 例子1：</p>
<pre name="code" class="python">while x:
    if match(x[0]):
	print 'Ni'
        break            # Exit, go around else &lt;--- 跳过 else:
    x = x[1:]
else:                             &lt;----- while 循环正常结束时执行 else:
    print 'Not found'
</pre>
&nbsp;
<p>&nbsp;&nbsp;&nbsp; 例子2：按行读文件内容</p>
<pre name="code" class="python">for line in open('test.txt'):
    print line
</pre>
&nbsp;
<p><strong>9. 用单元测试来保证软件的质量显得更加重要</strong></p>
<p>&nbsp;&nbsp;&nbsp; 来自：第15章 Function Basics</p>
<div class="quote_title">摘录： 写道</div>
<div class="quote_div">	<br />
	Of course, this polymorphic model of programming means we have to test our code<br />
	to detect errors, rather than providing type declarations a compiler can use to detect<br />
	some types of errors for us ahead of time. In exchange for an initial bit of testing,<br />
	though, we radically reduce the amount of code we have to write, and radically<br />
	increase our code&rsquo;s flexibility.<br />
</div>
<p>&nbsp;</p>
<p><strong>10.关于lambda的例子</strong>
</p>
<p>&nbsp;&nbsp;&nbsp; 来自：第17章 Advanced Function Topics</p>
<pre name="code" class="python">	f = lambda x, y, z: x + y + z   &lt;---- lambda = Anonymous Functions
	等同于
	def func(x, y, z): return x + y + z  
</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://fangzhouxing.javaeye.com/blog/199812#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/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/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 03 Jun 2008 17:49:12 +0800</pubDate>
        <link>http://fangzhouxing.javaeye.com/blog/199812</link>
        <guid>http://fangzhouxing.javaeye.com/blog/199812</guid>
      </item>
      <item>
        <title>Python/Django学习笔记(2)：感受Django框架</title>
        <author>fangzhouxing</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fangzhouxing.javaeye.com">fangzhouxing</a>&nbsp;
          链接：<a href="http://fangzhouxing.javaeye.com/blog/198908" style="color:red;">http://fangzhouxing.javaeye.com/blog/198908</a>&nbsp;
          发表时间: 2008年05月31日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>就像学习Ruby语言的主要动力来自RubyOnRails框架一样，学习Python语言是因为要用它来开发Web应用，而Django框架显然是首选。<br />
<br />
<strong>搭建Django开发环境</strong>
<br />
<br />
&nbsp;&nbsp;&nbsp; 1. 下载 django (0.96.1)<br />
<br />
&nbsp;&nbsp;&nbsp; 2. 按照<a href="http://www.djangoproject.com/documentation/install/">安装文档</a>
进行配置。<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这方面有价值的文档还有：<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://magpiebrain.com/blog/2006/10/09/using-eclipse-and-pydev-for-django/">Using Eclipse and PyDev for django</a>
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://hi.baidu.com/yobin/blog/item/3c7a39f3f466e555342acc05.html">安装配置Django开发环境（Eclipse + Pydev）(2008.4)</a>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://ddkangfu.blog.51cto.com/311989/63876">使用Eclipse+PyDev+EclipseHtmlEditor搭建Django开发环境</a>
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://honeyday.bokee.com/5747247.html ">在Windows上安装Django</a>
 <br />
<br />
&nbsp;&nbsp;&nbsp; 3. 注意要在 Path 中加入 python 安装路径.<br />
<br />
&nbsp;&nbsp;&nbsp; 4. 还要在 Path 中加入 &lt;python 安装路径&gt;\Lib\site-packages\django\bin 路径。<br />
<br />
<strong>跟着教程走一遍</strong>
<br />
<br />
&nbsp;&nbsp;&nbsp; 1. 从这篇<a href="http://www.djangoproject.com/documentation/tutorial01/ ">教程</a>
开始。<br />
<br />
&nbsp;&nbsp;&nbsp; 2. 基本过程如下：<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第1步: 创建项目<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第2步: 创建models<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第3步: Activate the admin site<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第4步: 创建view<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第5步: 创建表单(仅浏览)<br />
<br />
&nbsp;&nbsp;&nbsp; 3. 模拟出Eclipse的调试功能。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://hi.baidu.com/yobin/blog/item/3c7a39f3f466e555342acc05.html">安装配置Django开发环境（Eclipse + Pydev）</a>
<br />
<br />
<strong>阅读有关Django的资料</strong>
<br />
<br />
&nbsp;&nbsp; 1. 阅读《Next-Generation Web Frameworks in Python》 （April 9, 2007出版）<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其中有关Django的内容摘录如下：</p>
<pre name="code" class="java">      -- Django advocates a &quot;model-centric&quot; approach to development

      -- Django is different—it considers the view layer to be a combination of the
         templates and some backing Python methods in views.py.

      -- If Django has a controller layer (other than Django itself), it is the URL mapper.
         One Django design philosophy is to decouple the visible URLs in the browser from
         the application itself. This facilitates deployment and allows changes to the URL
         mapping to be independent of the methods that handle those URLs. This feature is
         configured in urls.py:
</pre>
&nbsp;
<p><br />
&nbsp;&nbsp; 2. 阅读《Professional Python Frameworks: Web 2.0 Programming with Django and Turbogears》（2007.10出版）<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 书中有一个完整的blog例子可以参考并作为学习例子(AJAX+RSS)。<br />
<br />
&nbsp;&nbsp; 3. 阅读《The Definitive Guide to Django: Web Development Done Right》（December 2007出版）<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第一遍阅读可能不一定能都懂，先花1天时间通读一遍。<br />
<br />
<strong>对Django框架的评估</strong>
<br />
<br />
&nbsp;&nbsp;&nbsp; 1. 与RubyOnRails的比较<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://jesusphreak.infogami.com/blog/why_py">Of snakes and rubies; Or why I chose Python over Ruby</a>
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://jesusphreak.infogami.com/blog/">Constructive reasons to use Django instead of Rails</a>
<br />
<br />
&nbsp;&nbsp;&nbsp; 2. 部分Django资源：<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="https://groups.google.com/group/python-cn?hl=zh-CN">python-cn`CPyUG`华蟒用户组</a>
<br />
<br />
&nbsp;&nbsp;&nbsp; 3. 关注Django的热部署问题。能否做到程序更新后自动加载呢？<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.blogjava.net/huanzhugege/archive/2007/03/12/103325.html">Python Module Auto Reload</a>
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这个问题暂时没有结果。</p>
          <br/>
          <span style="color:red;">
            <a href="http://fangzhouxing.javaeye.com/blog/198908#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/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/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 31 May 2008 09:56:01 +0800</pubDate>
        <link>http://fangzhouxing.javaeye.com/blog/198908</link>
        <guid>http://fangzhouxing.javaeye.com/blog/198908</guid>
      </item>
      <item>
        <title>Python/Django学习笔记(1)：初识Python语言</title>
        <author>fangzhouxing</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fangzhouxing.javaeye.com">fangzhouxing</a>&nbsp;
          链接：<a href="http://fangzhouxing.javaeye.com/blog/197871" style="color:red;">http://fangzhouxing.javaeye.com/blog/197871</a>&nbsp;
          发表时间: 2008年05月28日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>经过一个月的埋头学习，对Python语言和Django框架有了初步的掌握，现在已经进入实战阶段。<br />
从这一篇文章开始，对学习笔记进行整理发表。<br />
<br />
<strong>搜寻学习资料</strong>
<br />
<br />
&nbsp;&nbsp;&nbsp; 有关的学习材料在网站 <a href="http://slav0nic.org.ua/static/books/python/">http://slav0nic.org.ua/static/books/python/</a>
 中都有。</p>
<p>&nbsp;&nbsp;&nbsp; 值得关注的电子书如下：<br />
<br />
&nbsp;&nbsp;&nbsp; 关于Web框架&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; The Definitive Guide to Django: Web Development Done Right(December 2007)<br />
&nbsp;&nbsp;&nbsp; Professional Python Frameworks: Web 2.0 Programming with Django and Turbogears(2007.10)<br />
&nbsp;&nbsp;&nbsp; Next-Generation Web Frameworks in Python(April 9, 2007)<br />
<br />
&nbsp;&nbsp;&nbsp; Python语言入门<br />
&nbsp;&nbsp;&nbsp; Learning Python(第3版,2007.10)<br />
&nbsp;&nbsp;&nbsp; Beginning Python: From Novice to Professional(September 2005)<br />
&nbsp;&nbsp;&nbsp; Dive Into Python(2004.5)<br />
<br />
&nbsp;&nbsp;&nbsp; Python语言高级应用<br />
&nbsp;&nbsp;&nbsp; Programming Python (Third Edition)(August, 2006)<br />
&nbsp;&nbsp;&nbsp; Thinking in Python(December 2001)<br />
&nbsp;&nbsp;&nbsp; Python Cookbook(第2版,2005)<br />
<br />
<strong>搭建Python开发环境</strong>
<br />
<br />
&nbsp;&nbsp;&nbsp; 1. 阅读教程：<a href="http://www.fabioz.com/pydev/manual_101_root.html">http://www.fabioz.com/pydev/manual_101_root.html</a>
<br />
<br />
&nbsp;&nbsp;&nbsp; 2. 下载 Eclipse 3.3.2.<br />
<br />
&nbsp;&nbsp;&nbsp; 3. 下载 PyDev 1.3.15.<br />
<br />
&nbsp;&nbsp;&nbsp; 4. 下载 python-2.5.2.msi.<br />
<br />
&nbsp;&nbsp;&nbsp; 5. 按照文档配置 Eclipse.<br />
<br />
<strong>为何要切换到新语言？</strong>
<br />
<br />
&nbsp;&nbsp;&nbsp; 阅读文章&ldquo;<a href="http://news.csdn.net/n/20070612/105203.html">专访Python创始人：迎接Python3000 </a>
&rdquo;<br />
<br />
&nbsp;&nbsp;&nbsp; 文章摘录：</p>
<pre name="code" class="java"> 我想正因为没有哪个语言什么都能做，开发人员才真的需要去学习多门语言，并能够整合他们。

当你真的遇到这种情况，当你学会了许多种语言，突然遇到一个问题，用两行Ruby程序就解决了，
而如果用Java语言的话可能需要两百行，想想那是一种多么美妙的感觉。这会让你成为一个更好的
开发人员，因为你开始明白在不同的语言中如何使用不同的程序，你会从不同的语言中获取知识。
在 Python中有很酷的列表表达式，一行程序就可以处理一个列表中的各种迭代。
其实并不是说每个语言都是一个完全不同的世界，都需要你一切从头开始。
你学会了一个，认识了这个语言中一些独特的地方，然后学习了另一个，会发现有很多相似的地方。

从OO语言过渡到函数语言有那么一些不同之处。而像Ruby和Python这样的语言是跨OO和函数语言的，
使用这些语言可以帮你处理很多事情，同时还能够扩展你的视野。
</pre>
&nbsp;
<p><strong>了解Python的历史和现状</strong>
</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; Guido van Rossum是Python编程语言的创始人，现在就职于Google公司。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 1989年Guido在ABC与语言的基础上创建了Python语言。Python目前在很多方面都比Ruby更成熟，比如说它的运行速度更快、用户数量更多，而且支持第三方的编码软件数量也更大。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 访问Guido van Rossum的<a href="http://www.artima.com/weblogs/index.jsp?blogger=guido">博客</a>
。 &nbsp;&nbsp;</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://fangzhouxing.javaeye.com/blog/197871#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/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>Wed, 28 May 2008 15:17:01 +0800</pubDate>
        <link>http://fangzhouxing.javaeye.com/blog/197871</link>
        <guid>http://fangzhouxing.javaeye.com/blog/197871</guid>
      </item>
      <item>
        <title>第一个RESTful Web Service设计</title>
        <author>fangzhouxing</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fangzhouxing.javaeye.com">fangzhouxing</a>&nbsp;
          链接：<a href="http://fangzhouxing.javaeye.com/blog/195577" style="color:red;">http://fangzhouxing.javaeye.com/blog/195577</a>&nbsp;
          发表时间: 2008年05月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>下面是设计内容：</p>
<pre name="code" class="java">	HTTP方法       URI                   描述
	-----------    ---                   ----------------
	GET            /users                获取全部用户帐号
	POST           /users                创建用户帐号
	GET            /users/1              获取指定Id的用户帐号
	PUT            /users/1              修改指定Id的用户帐号
	DELETE         /users/1              删除指定Id的用户帐号
	PUT            /users/1/password     修改指定Id的用户的登录密码
	PUT            /users/1/password/default     重置密码
</pre>
<p>&nbsp;</p>
<p>关于uri结尾是否要加上斜杠(/)的问题，网上有很多争论，最终采用<a href="https://www.projectzero.org/download/doc/zero.doc.M5/zero.core/REST.html">Project Zero</a>
的做法，就是全部不加斜杠。</p>
<p>&nbsp;</p>
<p>有趣的是修改密码和重置密码的设计，要从传统的动作概念中解脱出来，将密码(password)和初始密码(password/default)本身作为资源来看待。</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://fangzhouxing.javaeye.com/blog/195577#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><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/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 22 May 2008 11:42:32 +0800</pubDate>
        <link>http://fangzhouxing.javaeye.com/blog/195577</link>
        <guid>http://fangzhouxing.javaeye.com/blog/195577</guid>
      </item>
      <item>
        <title>用预配置类设计模式重新实现Hello World例子</title>
        <author>fangzhouxing</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fangzhouxing.javaeye.com">fangzhouxing</a>&nbsp;
          链接：<a href="http://fangzhouxing.javaeye.com/blog/193544" style="color:red;">http://fangzhouxing.javaeye.com/blog/193544</a>&nbsp;
          发表时间: 2008年05月16日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>在ExtJS官方论坛上，jsakalos 提出了采用预配置类(Pre-configured classes)设计界面组件的模式。请看这里：<br />
（1）<a href="http://extjs.com/forum/showthread.php?t=32292">http://extjs.com/forum/showthread.php?t=32292</a>
<br />
（2）<a href="http://extjs.com/forum/showthread.php?t=26728">http://extjs.com/forum/showthread.php?t=26728</a>
</p>
<p>一直不太习惯这种方式。最近有机会重构原有项目的ExtJS源代码，想使用这种新模式。作为练习，重新实现了ExtJS发行包中的Hello World例子(examples\window\hello.html)。</p>
<p>&nbsp;</p>
<p>解开附件，拷贝其中的文件到 examples\window 目录即可（在ExtJS 2.1下测试通过）。</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://fangzhouxing.javaeye.com/blog/193544#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/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, 16 May 2008 10:13:34 +0800</pubDate>
        <link>http://fangzhouxing.javaeye.com/blog/193544</link>
        <guid>http://fangzhouxing.javaeye.com/blog/193544</guid>
      </item>
      <item>
        <title>JavaScript的局部变量没有块级作用域</title>
        <author>fangzhouxing</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fangzhouxing.javaeye.com">fangzhouxing</a>&nbsp;
          链接：<a href="http://fangzhouxing.javaeye.com/blog/193197" style="color:red;">http://fangzhouxing.javaeye.com/blog/193197</a>&nbsp;
          发表时间: 2008年05月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><br />
一直以为JavaScript的变量和其他语言（如Java)一样，有块级作用域。今天看到了这样的代码：</p>
<p><br />
<img src="http://seamextsample.googlecode.com/files/aa.GIF" alt="" />
</p>
<p>&nbsp;</p>
<p>显然JavaScript的局部变量作用域应属于函数级作用域，即在一个函数中声明的变量，无论是在哪里声明的，在整个函数中它们都是有定义的（详见<a href="http://ooboy.net/blog/blogview.asp?logID=420">这里</a>
）。</p>
<p>&nbsp;</p>
<p><img src="http://seamextsample.googlecode.com/files/aa2.GIF" alt="" />
</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://fangzhouxing.javaeye.com/blog/193197#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><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/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 15 May 2008 10:40:59 +0800</pubDate>
        <link>http://fangzhouxing.javaeye.com/blog/193197</link>
        <guid>http://fangzhouxing.javaeye.com/blog/193197</guid>
      </item>
      <item>
        <title>巧用CSS避免ExtJS应用界面同质化</title>
        <author>fangzhouxing</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fangzhouxing.javaeye.com">fangzhouxing</a>&nbsp;
          链接：<a href="http://fangzhouxing.javaeye.com/blog/192821" style="color:red;">http://fangzhouxing.javaeye.com/blog/192821</a>&nbsp;
          发表时间: 2008年05月14日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          ExtJS强大的界面组件，让程序员在美工不参与的情况也能开发出Web界面。然而，可能带来的问题就是Web应用软件界面的同质化。<br /><br />最近有时间仔细研究了几个ExtJS应用的实现细节，发现可以结合组件的id值和CSS，达到界面外观定制的效果。<br /><br />不过，ExtJS官方好像没有提供这方面的文档，所以其规律很难系统化。有兴趣的同学可以从附件中体会这种用法。<br /><br />附件中的程序在ExtJS 2.1下测试通过。解开后直接把其中的文件拷贝到 ext-2.1\examples\panel 即可。<br /><br />主要功能如下：<br />1.例子1：f1.html<br />（1）用CSS改变工具条背景样式<br />参照了：http://extjs.com/forum/showthread.php?t=26639<br />（2）用图片代替“图标+文字”按钮<br />参照了：http://www.extjs.com/forum/showthread.php?t=16408<br />（3）用CSS改变面板背景颜色<br />（4）用CSS改变面板在页面上的位置<br />2.例子2：f2.html<br />（1）用CSS改变工具条背景样式<br />（2）用CSS改变工具条按钮的样式
          <br/>
          <span style="color:red;">
            <a href="http://fangzhouxing.javaeye.com/blog/192821#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/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><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 14 May 2008 09:20:29 +0800</pubDate>
        <link>http://fangzhouxing.javaeye.com/blog/192821</link>
        <guid>http://fangzhouxing.javaeye.com/blog/192821</guid>
      </item>
      <item>
        <title>突然理解了JavaScript自调用函数的用处</title>
        <author>fangzhouxing</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fangzhouxing.javaeye.com">fangzhouxing</a>&nbsp;
          链接：<a href="http://fangzhouxing.javaeye.com/blog/192203" style="color:red;">http://fangzhouxing.javaeye.com/blog/192203</a>&nbsp;
          发表时间: 2008年05月12日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>JavaScript自调用函数(self-invoking function)的例子，可以参见<a href="http://www.dustindiaz.com/awkward-looking-javascript/">这里</a>
。</p>
<p>我原来的程序是这样写的，使用了所谓的&ldquo;<a href="http://www.thinksharp.org/creating-a-javascript-singleton-object/">单件对象</a>
&rdquo;(Singleton object)的设计模式：</p>
<pre name="code" class="js">Divo = function() {
    return {
    init : function() {
      //这里执行所有初始化功能
    }
}()

Divo.init()
</pre>
<p>现在，改用自调用函数方式，写成这样：</p>
<pre name="code" class="js">(function() {

    //这里执行所有初始化功能

})();
</pre>
<p>好处：<br />
原来的做法中，Divo 对象中 init 函数一直存在，显然会占用内存（这一点我原来没有意识到）。<br />
当然，你也可以在执行 Divo.init() 后，做 delete Divo.init。</p>
<p>因为在整个应用程序生命周期中, init 函数只需要执行一次，所以自调用函数是最简洁的一种写法。</p>
&nbsp;
<p>&nbsp;</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://fangzhouxing.javaeye.com/blog/192203#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/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><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>Mon, 12 May 2008 13:22:38 +0800</pubDate>
        <link>http://fangzhouxing.javaeye.com/blog/192203</link>
        <guid>http://fangzhouxing.javaeye.com/blog/192203</guid>
      </item>
      <item>
        <title>发现JavaScript中可以替代if条件语句的一种简洁写法</title>
        <author>fangzhouxing</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fangzhouxing.javaeye.com">fangzhouxing</a>&nbsp;
          链接：<a href="http://fangzhouxing.javaeye.com/blog/192139" style="color:red;">http://fangzhouxing.javaeye.com/blog/192139</a>&nbsp;
          发表时间: 2008年05月12日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>例如，传统的写法：</p>
<p>&nbsp;</p>
<pre name="code" class="java">if (!adding)
    win.hide()</pre>
<p>&nbsp;可以写成下面的形式，效果相同：</p>
<pre name="code" class="java">adding || win.hide()</pre>
<p>如果是赋值语句，要注意整个语句用括号括起来，例如:</p>
<p>&nbsp;</p>
<pre name="code" class="java">url || ( url = '.force_logout');</pre>
&nbsp;
<p>&nbsp;</p>
<p>可以代替下面的写法:</p>
<pre name="code" class="java">if (!url)
   url = '.force_logout'

</pre>
&nbsp;
          <br/>
          <span style="color:red;">
            <a href="http://fangzhouxing.javaeye.com/blog/192139#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></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 12 May 2008 10:36:48 +0800</pubDate>
        <link>http://fangzhouxing.javaeye.com/blog/192139</link>
        <guid>http://fangzhouxing.javaeye.com/blog/192139</guid>
      </item>
      <item>
        <title>自己写的第一个python程序</title>
        <author>fangzhouxing</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fangzhouxing.javaeye.com">fangzhouxing</a>&nbsp;
          链接：<a href="http://fangzhouxing.javaeye.com/blog/189575" style="color:red;">http://fangzhouxing.javaeye.com/blog/189575</a>&nbsp;
          发表时间: 2008年05月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>写了第一个python程序，感觉很爽。</p>
<pre name="code" class="java">files = []
file_object = open('G:\_python\package.txt')
try:
    for line in file_object:
	line = line.rstrip()
	if line.endswith('.js'):
  	   [obj_name,file_name] = line.split(',')
	   ns = obj_name.split('.')
	   if file_name.startswith('//'):
	      full_name = 'app//%s' % file_name
	   else:
		if len(ns) == 4:
		   full_name = 'app//%s//%s//%s' % (ns[1],ns[2],file_name)
		else:
		   full_name = 'app//%s//%s' % (ns[1],file_name)
           if full_name not in files:
	      files.append(full_name)
finally:
    file_object.close()

print files
print tuple(files)
</pre>
&nbsp;
<p>package.txt中的内容如下：</p>
<pre name="code" class="java">MainObjectName,FileName

Divo.app.ChangePassword,ChangePassword.js
Divo.app.ChangePassword,/common/form/passwordfield/js/Ext.ux.PasswordField.js

Divo.app.ChangePassword,/common/form/passwordfield/js/Ext.ux.PasswordField.js
Divo.app.misc.Support,Support.js
</pre>
&nbsp;
          <br/>
          <span style="color:red;">
            <a href="http://fangzhouxing.javaeye.com/blog/189575#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/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></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 05 May 2008 08:29:25 +0800</pubDate>
        <link>http://fangzhouxing.javaeye.com/blog/189575</link>
        <guid>http://fangzhouxing.javaeye.com/blog/189575</guid>
      </item>
      <item>
        <title>Google App Engine的HelloWorld程序运行通过</title>
        <author>fangzhouxing</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fangzhouxing.javaeye.com">fangzhouxing</a>&nbsp;
          链接：<a href="http://fangzhouxing.javaeye.com/blog/184621" style="color:red;">http://fangzhouxing.javaeye.com/blog/184621</a>&nbsp;
          发表时间: 2008年04月20日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>开始学习和使用Google App Engine, 并把HelloWorld程序运行起来了.</p>
<div class="quote_title"> app.yaml</div>
<div class="quote_div">application: helloworld<br />
version: 1<br />
runtime: python<br />
api_version: 1<br />
<br />
handlers:<br />
- url: /.*<br />
  script: helloworld.py</div>
<p>&nbsp;&nbsp;&nbsp; helloworld.py(加入了中文测试)</p>
<div class="quote_div">#coding=utf-8<br />
print 'Content-Type: text/plain'<br />
print ''<br />
s = 'Hello, world!中文123'<br />
print unicode(s,&quot;utf-8&quot;).encode(&quot;gbk&quot;)<br />
</div>
&nbsp;
<p>&nbsp;显示中文真的如此麻烦吗?</p>
          <br/>
          <span style="color:red;">
            <a href="http://fangzhouxing.javaeye.com/blog/184621#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/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>Sun, 20 Apr 2008 18:47:53 +0800</pubDate>
        <link>http://fangzhouxing.javaeye.com/blog/184621</link>
        <guid>http://fangzhouxing.javaeye.com/blog/184621</guid>
      </item>
      <item>
        <title>让Java更像JavaScript，而让JavaScript更像Java</title>
        <author>fangzhouxing</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fangzhouxing.javaeye.com">fangzhouxing</a>&nbsp;
          链接：<a href="http://fangzhouxing.javaeye.com/blog/160041" style="color:red;">http://fangzhouxing.javaeye.com/blog/160041</a>&nbsp;
          发表时间: 2008年01月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>在JBoss Seam+ExtJS项目中，用Groovy代替Java编写Seam组件，可以让Java更像JavaScript，用JavaScript的感觉去写Java程序变成现实，使代码简洁清晰。在客户端UI层，通过引入命名空间(namespace)机制和编程约定，可以让JavaScript更像Java, 提高JavaScript程序的可读性和可维护性。<br />
<br />
<strong><span style="font-family: 宋体;">1.让Java更像JavaScript</span>
</strong>
<br />
<br />
（1）创建类实例<br />
<br />
JavaScript:</p>
<pre name="code" class="js">        var addBtn = new Ext.Toolbar.Button({
            text : '新建',
            tooltip : '新建角色',
            icon : Divo.getIconAdd(),
            cls : 'x-btn-text-icon',
            handler : addRole
        })

</pre>
<p>&nbsp;<br />
Groovy:</p>
<pre name="code" class="java">         def doc = new DocumentUser(
             userId : 1L,
             docId : 1L,
             canRead : 1,
             canWrite : 0
         ))
</pre>
<p>&nbsp;<br />
<br />
（2）类中的方法定义<br />
<br />
JavaScript:</p>
<pre name="code" class="js">    function onRoleMainted(subj, msg, data) {
        ...
    }
</pre>
<p>&nbsp;<br />
<br />
Groovy:</p>
<pre name="code" class="java">    def addPermissions(ss, userId) {
           ...
    }
</pre>
<p>&nbsp;<br />
<br />
（3）声明类属性<br />
<br />
JavaScript:</p>
<pre name="code" class="js">    Divo.app.role.Role = function() {

        var actions
        var meta, smartGrid, grid, ds, selModel, tb
        ...

     }()

</pre>
<p>&nbsp;<br />
Groovy:</p>
<pre name="code" class="java">    class ContentDragServiceTest {
    
        def _service
        def nodeC1,nodeC11,nodeC12,nodeC111,nodeC112,nodeC113

        ...

    }
</pre>
<p><br />
<strong>2.让JavaScript更像Java</strong>
<br />
<br />
（1）与Java中的包(package)机制类似，在JavaScript中引入命名空间，避免对象名冲突<br />
<br />
Groovy:</p>
<pre name="code" class="java">    package com.divo.doc.service

    class DocumentService {
        ...
    }
</pre>
<p>&nbsp;<br />
<br />
JavaScript:</p>
<pre name="code" class="js">    Ext.namespace(&quot;Divo.app.role&quot;)

    Divo.app.role.Role = function() {
         ...
    }
</pre>
<p>&nbsp;<br />
（2）JavaScript中，约定js文件名等于类名或对象名，目录名对应命名空间名<br />
<img src="http://seamextsample.googlecode.com/files/pp.GIF" alt="" />
<br />
<br />
（3）JavaScript中，大小写约定与Java一致<br />
<br />
Groovy:</p>
<pre name="code" class="java">   def createDir(Document obj) {
        def dir = testing?DIR:AppUtil.getRootDir()+DIR
        if (!(new File(dir+obj.dirName)).exists()) {    
            if (!(new File(dir+obj.dirName)).mkdir())
                   throw new Exception(&quot;无法创建目录&quot;+dir+obj.dirName)
        }
    }
</pre>
<p>&nbsp;<br />
&nbsp;JavaScript:</p>
<pre name="code" class="js">       function init() {
            oRoleForm = Divo.app.role.RoleForm

            Divo.subscribe(Divo.app.role.ROLE_MAINT, onRoleMainted, this)

            createHTML()
            createGridMeta()
            createGrid()
        }
</pre>
<p>&nbsp;</p>
<p>（4）JavaScript中，不用分号作为语句结束符，与Groovy一致。</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://fangzhouxing.javaeye.com/blog/160041#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><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/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>Tue, 29 Jan 2008 09:47:51 +0800</pubDate>
        <link>http://fangzhouxing.javaeye.com/blog/160041</link>
        <guid>http://fangzhouxing.javaeye.com/blog/160041</guid>
      </item>
      <item>
        <title>在“JBoss Seam+ExtJS”项目中使用Groovy代替Java</title>
        <author>fangzhouxing</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fangzhouxing.javaeye.com">fangzhouxing</a>&nbsp;
          链接：<a href="http://fangzhouxing.javaeye.com/blog/157882" style="color:red;">http://fangzhouxing.javaeye.com/blog/157882</a>&nbsp;
          发表时间: 2008年01月20日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>阅读了《Groovy In Action》一书，做了网上调研，经历了最初的FUD（Fear, uncertainty, doubt ）过程，最终决定使用Groovy代替Java来写JBoss Seam组件。</p>
<p>&nbsp;</p>
<p>本文是近一个月来, 使用Groovy编程的几点粗浅的体会。最后展示了一些Groovy源代码。</p>
<p>&nbsp;</p>
<p><strong>1.好处</strong>
</p>
<p>&nbsp;</p>
<p>（1）代码变得非常简洁，能够直接把程序的意图表现出来。同样的功能，很难想象再回到Java去编程。</p>
<p>（2）闭包(Closure)的使用，大大简化了某些算法，尤其是集合操作，开发效率大为提高。</p>
<p>（3）可以用JavaScript的感觉去写Groovy程序，因为两者都属于动态类型语言。</p>
<p>&nbsp;</p>
<p><strong>2.不便之处</strong>
</p>
<p>&nbsp;</p>
<p>（1）Groovy Eclipse Plugin的当前版本（2008-01-03发表）的编译速度还比较慢，功能上太弱。希望在未来的几个月中，这种情况能得到改变。</p>
<p>（2）编译阶段，对方法名引用错误，或者方法传递参数的错误，不再提示，要等到运行时才能发现。</p>
<p>（3）GlassFish中检测不到Groovy编写的类的修改，无法获得自动加载的热部署好处。&nbsp;</p>
<p>&nbsp;</p>
<p><strong>3.不确定之处</strong>
</p>
<p>&nbsp;</p>
<p>（1）是否会影响到整个后台程序的运行速度？</p>
<p>（2）是否能被开发团队中其他成员接受和欢迎？&nbsp;</p>
<p>&nbsp;</p>
<p><strong>4.Groovy代码展示1：Hibernate实体类</strong>
</p>
<pre name="code" class="java">package com.divo.app.domain

import javax.persistence.*
import org.jboss.seam.annotations.*

//网格视图-用户版本
@Entity
@Name(&quot;app.myGridView&quot;)
@Table(name=&quot;app_MyGridView&quot;,uniqueConstraints = [
   @UniqueConstraint(columnNames =
   [&quot;viewId&quot;, &quot;userId&quot;] )
])
class MyGridView {
    
    @Id 
    @GeneratedValue(strategy = GenerationType.TABLE, generator=&quot;appNextId&quot;)
    @TableGenerator(name=&quot;appNextId&quot;, table=&quot;app_NextId&quot;, allocationSize=1)
    Long id
    
    @Column(nullable=false)
    Long userId
    
    @Column(nullable=false)
    Long viewId
    
    @Column(nullable=false,length=4000)
    String viewState
	
}
//EOP
</pre>
<p>&nbsp;</p>
&nbsp;
<p><strong>5.Groovy代码展示2：作为JBoss Seam组件的服务类</strong>
</p>
<pre name="code" class="java">package com.divo.app.service

import org.hibernate.*

import org.jboss.seam.annotations.*
import org.jboss.seam.security.*

import com.divo.app.domain.*
import com.divo.core.misc.*
import com.divo.core.util.*

@Name(&quot;app.appInfoService&quot;)
@AutoCreate
class AppInfoService extends BaseService {

    String appInfoFileName
    
    def getAppInfo() {
	    def dir = appInfoFileName?&quot;&quot;:AppUtil.getRootDir() 
	
	    def s = Constants.FILE_SEPARATOR
	    def fileName = appInfoFileName?appInfoFileName:&quot;app${s}version.txt&quot;
	    def file = new File(dir+fileName)
	    def appInfo = new AppInfo() 
		
	    def count = 0
	    file.splitEachLine(/\,/){
		    if (it.size()&gt;1 &amp;&amp; count&gt;0) {
				appInfo.version = it[0]
				appInfo.buildId = it[1]
				appInfo.copyright = it[2]
				appInfo.productName = it[3]
				appInfo.isDebug = (it[6]==&quot;Y&quot; || it[6]==&quot;y&quot;)
		    }
		    count++
	    }	    
	   appInfo.currentDate = DateTimeUtil.getNowDate()
	   appInfo.contextPath = appInfoFileName?&quot;&quot;:AppUtil.getContextPath() 
	   appInfo
    }
    
}
//EOP
</pre>
&nbsp;&nbsp;
<p><strong>6.Groovy代码展示3：单元测试类</strong>
</p>
<p>&nbsp;</p>
<pre name="code" class="java">package com.divo.app.service.test

import org.testng.annotations.*
import com.divo.app.service.*
import com.divo.core.util.*
import com.divo.core.misc.*

class AppInfoServiceTest extends AppTestCase {

    def _service
    
    @BeforeClass
    @Override
    void init() {
        super.init()
        
        _service = new AppInfoService()
    }
   
    @BeforeMethod
    @Override
    void begin() {
        super.begin()
        
        _service.setSession(session)
    }
    
    @Test 
    void canGetAppInfo() {
	    _service.appInfoFileName = &quot;test//version.txt&quot;  
	    def appInfo = _service.getAppInfo()
	    def currentDate = DateTimeUtil.getNowDate()	    
	    
	    assert appInfo.version==&quot;2.0.0-b1&quot;
	    assert appInfo.buildId==&quot;2008020112&quot;
	    assert appInfo.copyright==&quot;fzx&quot;
	    assert appInfo.productName==&quot;软件问题跟踪系统&quot;
	    assert appInfo.currentDate==currentDate
    }
    
}
//EOP</pre>
&nbsp;
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://fangzhouxing.javaeye.com/blog/157882#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><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>Sun, 20 Jan 2008 20:41:51 +0800</pubDate>
        <link>http://fangzhouxing.javaeye.com/blog/157882</link>
        <guid>http://fangzhouxing.javaeye.com/blog/157882</guid>
      </item>
      <item>
        <title>JBoss Seam without JSF</title>
        <author>fangzhouxing</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fangzhouxing.javaeye.com">fangzhouxing</a>&nbsp;
          链接：<a href="http://fangzhouxing.javaeye.com/blog/157878" style="color:red;">http://fangzhouxing.javaeye.com/blog/157878</a>&nbsp;
          发表时间: 2008年01月20日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>在&ldquo;<a href="JBoss Seam (POJO without EJB) 后台 + ExtJS 前台完整例子" target="_blank">JBoss Seam (POJO without EJB) 后台 + ExtJS 前台完整例子</a>
&rdquo;中，在FireFox下运行该项目，会看到中文乱码，但在IE下能正常显示中文。这个问题一致无法解决。此问题的详细内容，请参见这个<a href="http://groups.google.com/group/jbossseam/browse_thread/thread/40337062f7199f5e/e87149e13ade60eb#e87149e13ade60eb" target="_blank">帖子</a>
。</p>
<p>&nbsp;</p>
<p>最后想到了不用JSF，直接在Servlet中产生页面内容，避免了中文乱码问题。</p>
<p>&nbsp;</p>
<pre name="code" class="java">package org.jboss.seam.example.divo;
。。。
public class SampleServlet extends BaseServlet {

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	String action = request.getParameter(&quot;action&quot;);

	if (action.equals(&quot;showHome&quot;))
	    runShowHome(request, response);
    }

    
    /**
     * 显示首页
     */
    private void runShowHome(HttpServletRequest request, HttpServletResponse response) throws IOException {
	String path = request.getContextPath();
	response.setContentType(&quot;text/html;charset=GBK&quot;);
	PrintWriter out = response.getWriter();
	out.println(&quot;&lt;html&gt;&quot;);
	out.println(&quot;&lt;head&gt;&quot;);
	out.println(&quot;&lt;title&gt;JBoss Suites: Seam Framework&lt;/title&gt;&quot;);
	
	out.println(&quot;&lt;!--{{{ css --&gt;&quot;);
	
	out.println(&quot;&lt;link rel=\&quot;stylesheet\&quot; href=\&quot;&quot;+path+&quot;/public/css/ext-all.css\&quot; type=\&quot;text/css\&quot; /&gt;&quot;);
	out.println(&quot;&lt;link rel=\&quot;stylesheet\&quot; href=\&quot;&quot;+path+&quot;/public/css/divo.css\&quot; type=\&quot;text/css\&quot; /&gt;&quot;);

	out.println(&quot;&lt;link rel=\&quot;stylesheet\&quot; href=\&quot;&quot;+path+&quot;/app/css/screen.css\&quot; type=\&quot;text/css\&quot; /&gt;&quot;);
	out.println(&quot;&lt;link rel=\&quot;stylesheet\&quot; href=\&quot;&quot;+path+&quot;/app/status-bar.css\&quot; type=\&quot;text/css\&quot; /&gt;&quot;);
	out.println(&quot;&lt;!-- }}} --&gt;&quot;);
		
	out.println(&quot;&lt;/head&gt;&quot;);

	out.println(&quot;&lt;body id=\&quot;pgHome\&quot;&gt;&quot;);

	out.println(&quot;&lt;div id=\&quot;divo-loading-msg\&quot;&gt;&quot;);
	out.println(&quot;	&lt;div&gt;Loading...&lt;/div&gt;&quot;);
	out.println(&quot;&lt;/div&gt;&quot;);
		
	out.println(&quot;&lt;!--{{{ seam remoting --&gt;&quot;);
	out.println(&quot;&lt;script type=\&quot;text/javascript\&quot; src=\&quot;&quot;+path+&quot;/seam/resource/remoting/resource/remote.js\&quot;&gt;&lt;/script&gt;&lt;script type=\&quot;text/javascript\&quot; src=\&quot;&quot;+path+&quot;/seam/resource/remoting/interface.js?sampleFacade\&quot;&gt;&lt;/script&gt;&quot;);
	out.println(&quot;&lt;!-- }}} --&gt;&quot;);
		
	out.println(&quot;&lt;!--{{{ js --&gt;&quot;);

	out.println(&quot;&lt;script type=\&quot;text/javascript\&quot; src=\&quot;&quot;+path+&quot;/public/js/ext-base.js\&quot;&gt;&lt;/script&gt;&quot;);

	out.println(&quot;&lt;script type=\&quot;text/javascript\&quot; src=\&quot;&quot;+path+&quot;/public/js/ext-all.js\&quot;&gt;&lt;/script&gt;&quot;);
	out.println(&quot;&lt;script type=\&quot;text/javascript\&quot; src=\&quot;&quot;+path+&quot;/public/js/pagebus.js\&quot;&gt;&lt;/script&gt;&quot;);
	out.println(&quot;&lt;script type=\&quot;text/javascript\&quot; src=\&quot;&quot;+path+&quot;/public/js/seam.js\&quot;&gt;&lt;/script&gt;&quot;);
	out.println(&quot;&lt;script type=\&quot;text/javascript\&quot; src=\&quot;&quot;+path+&quot;/public/js/divo.js\&quot; charset=\&quot;GBK\&quot;&gt;&lt;/script&gt;&quot;);

	out.println(&quot;&lt;script type=\&quot;text/javascript\&quot; src=\&quot;&quot;+path+&quot;/app/common.js\&quot;&gt;&lt;/script&gt;&quot;);
	out.println(&quot;&lt;script type=\&quot;text/javascript\&quot; src=\&quot;&quot;+path+&quot;/app/status-bar.js\&quot;&gt;&lt;/script&gt;&quot;);
	out.println(&quot;&lt;script type=\&quot;text/javascript\&quot; src=\&quot;&quot;+path+&quot;/app/home2.js\&quot;&gt;&lt;/script&gt;&quot;);
	out.println(&quot;&lt;!-- }}} --&gt;&quot;);
	out.println(&quot;&lt;div id=\&quot;status-bar\&quot;&gt;&quot;);
	out.println(&quot;  &lt;img id=\&quot;status-bar-close\&quot; src=\&quot;&quot;+path+&quot;/public/images/tab-close.gif\&quot; /&gt;&quot;);
	out.println(&quot;  &lt;span id=\&quot;status-msg\&quot;&gt;&lt;/span&gt;&quot;);
	out.println(&quot;&lt;/div&gt;&quot;);
		
	out.println(&quot;&lt;div id=\&quot;document\&quot;&gt;&quot;);

	out.println(&quot;	&lt;div id=\&quot;header\&quot;&gt;&quot;);
	out.println(&quot;		&lt;div id=\&quot;title\&quot;&gt;&lt;img src=\&quot;&quot;+path+&quot;/app/img/hdr.title.gif\&quot; alt=\&quot;JBoss Suites: seam framework demo\&quot; /&gt;&lt;/div&gt;&quot;);
	out.println(&quot;	&lt;/div&gt;&quot;);
	out.println(&quot;	&lt;div id=\&quot;container\&quot;&gt;&quot;);

	out.println(&quot;		&lt;div id=\&quot;sidebar\&quot;&gt;&quot;);
	out.println(&quot;			&lt;fieldset&gt;&quot;);
	out.println(&quot;				&lt;div&gt;登录名&lt;input id=\&quot;login-username\&quot; type=\&quot;text\&quot; style=\&quot;width: 175px;\&quot; /&gt;&quot;);
	out.println(&quot;				&lt;/div&gt;&quot;);
	out.println(&quot;				&lt;div&gt;密码&lt;input id=\&quot;login-password\&quot; type=\&quot;password\&quot; style=\&quot;width: 175px;\&quot; /&gt;&quot;);
	out.println(&quot;				&lt;/div&gt;&lt;br /&gt;&quot;);
	out.println(&quot;				&lt;center&gt;&lt;div class=\&quot;buttonBox\&quot;&gt;&lt;span id=\&quot;login-login\&quot; style=\&quot;cursor:pointer;\&quot;&gt;登录&lt;/span&gt;&lt;/div&gt;&lt;/center&gt;&lt;br /&gt;&quot;);
	out.println(&quot;				&lt;div class=\&quot;notes\&quot;&gt;&lt;span id=\&quot;login-register\&quot; style=\&quot;TEXT-DECORATION: underline;cursor:pointer;color:blue\&quot;&gt;注册新用户&lt;/span&gt;&lt;/div&gt;&quot;);
	out.println(&quot;			&lt;/fieldset&gt;&quot;);

	out.println(&quot;		&lt;/div&gt;&quot;);
	out.println(&quot;	&lt;/div&gt;&quot;);

	out.println(&quot;	&lt;div id=\&quot;footer\&quot;&gt;&quot;);
	out.println(&quot;	JBoss Seam 2.0(POJO without EJB)、Hibernate 3 和 Ext 2.0&quot;);
	out.println(&quot;	&lt;/div&gt;&quot;);

	out.println(&quot;&lt;/div&gt;&quot;);
	out.println(&quot;&lt;/body&gt;&quot;);
	out.println(&quot;&lt;/html&gt;&quot;);
    }
</pre>
&nbsp;
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://fangzhouxing.javaeye.com/blog/157878#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/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>Sun, 20 Jan 2008 20:27:36 +0800</pubDate>
        <link>http://fangzhouxing.javaeye.com/blog/157878</link>
        <guid>http://fangzhouxing.javaeye.com/blog/157878</guid>
      </item>
      <item>
        <title>JBoss Seam (POJO without EJB) 后台 + ExtJS 前台完整例子（十二）</title>
        <author>fangzhouxing</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fangzhouxing.javaeye.com">fangzhouxing</a>&nbsp;
          链接：<a href="http://fangzhouxing.javaeye.com/blog/147608" style="color:red;">http://fangzhouxing.javaeye.com/blog/147608</a>&nbsp;
          发表时间: 2007年12月11日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h1>JBoss Seam (POJO without EJB) 后台 + ExtJS 前台完整例子（十二）</h1>
<br />
<strong>1.引言</strong><br />
<br />
测试驱动开发（Test-Driven Development）的基本思路就是通过测试来推动整个开发的进行。设计思路定下来以后，先编写测试程序，然后再实现被测试的功能。这个习惯的形成将显著地提高软件的质量。<br />
<br />
针对服务层的单元测试，本项目构建了一个完整的测试环境。本文介绍测试环境构建的设计思路。<br />
<br />
<strong>2.单元测试应该测试什么?</strong><br />
<br />
在<a href="http://fangzhouxing.javaeye.com/blog/147125">这篇文章</a>中，介绍了本项目的分层设计方法。作为设计原则，远程外观和Servlet中不应该有太多的业务逻辑，具体功能必须由服务层实现。因此我认为没有必要对远程外观和Servlet进行测试。<br />
<br />
我在本项目中提倡的领域模型层的设计，基本上可以归为所谓&ldquo;贫血领域模型&rdquo;（<a href="http://www.martinfowler.com/bliki/AnemicDomainModel.html">Anemic Domain Model</a>）这种架构模式，因为没有太多的领域逻辑，所以也不必去对它们做单元测试了。<br />
<br />
最后，真正需要单元测试的就剩下了服务层！本项目围绕服务层构建了一个完整的单元测试环境。<br />
<br />
<strong>3.测试环境设计</strong><br />
<br />
由于遵循POJO without EJB设计原则，本项目中的单元测试是在完全脱离Seam框架下进行的。测试环境设计的要点说明如下：<br />
<br />
（1）测试数据库和开发数据库分开，用Ant目标切换：<br />
<div class="code_title">xml 代码</div>
<div class="dp-highlighter">
<div class="bar"> </div>
<ol class="dp-xml" start="1">
    <li class="alt"><span><span class="tag">&lt;</span><span class="tag-name">target</span><span>    </span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;copy-config-dev&quot;</span><span> </span><span class="tag">&gt;</span><span>  </span></span></li>
    <li class=""><span>      <span class="tag">&lt;</span><span class="tag-name">concat</span><span> </span><span class="attribute">destfile</span><span>=</span><span class="attribute-value">&quot;WEB-INF/src/hibernate.cfg.xml&quot;</span><span class="tag">&gt;</span><span>  </span></span></li>
    <li class="alt"><span>          <span class="tag">&lt;</span><span class="tag-name">filelist</span><span> </span><span class="attribute">dir</span><span>=</span><span class="attribute-value">&quot;config/db&quot;</span><span>              </span><span class="attribute">files</span><span>=</span><span class="attribute-value">&quot;head.xml&quot;</span><span> </span><span class="tag">/&gt;</span><span>  </span></span></li>
    <li class=""><span>          <span class="tag">&lt;</span><span class="tag-name">filelist</span><span> </span><span class="attribute">dir</span><span>=</span><span class="attribute-value">&quot;config/db&quot;</span><span>              </span><span class="attribute">files</span><span>=</span><span class="attribute-value">&quot;datasource-dev.xml&quot;</span><span> </span><span class="tag">/&gt;</span><span>  </span></span></li>
    <li class="alt"><span>          <span class="tag">&lt;</span><span class="tag-name">filelist</span><span> </span><span class="attribute">dir</span><span>=</span><span class="attribute-value">&quot;config/db&quot;</span><span>              </span><span class="attribute">files</span><span>=</span><span class="attribute-value">&quot;sample.xml&quot;</span><span> </span><span class="tag">/&gt;</span><span>  </span></span></li>
    <li class=""><span>          <span class="tag">&lt;</span><span class="tag-name">filelist</span><span> </span><span class="attribute">dir</span><span>=</span><span class="attribute-value">&quot;config/db&quot;</span><span>              </span><span class="attribute">files</span><span>=</span><span class="attribute-value">&quot;end.xml&quot;</span><span> </span><span class="tag">/&gt;</span><span>  </span></span></li>
    <li class="alt"><span>      <span class="tag"><!--</span--><span class="tag-name">concat</span><span class="tag">&gt;</span><span>  </span></span></span></li>
    <li class=""><span>  <span class="tag"><!--</span--><span class="tag-name">target</span><span class="tag">&gt;</span><span>  </span></span></span></li>
    <li class="alt"><span>  </span></li>
    <li class=""><span>  <span class="tag">&lt;</span><span class="tag-name">target</span><span>    </span><span class="attribute">name</span><span>=</span><span class="attribute-value">&quot;copy-config-test&quot;</span><span> </span><span class="tag">&gt;</span><span>  </span></span></li>
    <li class="alt"><span>      <span class="tag">&lt;</span><span class="tag-name">concat</span><span> </span><span class="attribute">destfile</span><span>=</span><span class="attribute-value">&quot;WEB-INF/src/hibernate.cfg.xml&quot;</span><span class="tag">&gt;</span><span>  </span></span></li>
    <li class=""><span>          <span class="tag">&lt;</span><span class="tag-name">filelist</span><span> </span><span class="attribute">dir</span><span>=</span><span class="attribute-value">&quot;config/db&quot;</span><span>              </span><span class="attribute">files</span><span>=</span><span class="attribute-value">&quot;head.xml&quot;</span><span> </span><span class="tag">/&gt;</span><span>  </span></span></li>
    <li class="alt"><span>          <span class="tag">&lt;</span><span class="tag-name">filelist</span><span> </span><span class="attribute">dir</span><span>=</span><span class="attribute-value">&quot;config/db&quot;</span><span>              </span><span class="attribute">files</span><span>=</span><span class="attribute-value">&quot;datasource-test.xml&quot;</span><span> </span><span class="tag">/&gt;</span><span>  </span></span></li>
    <li class=""><span>          <span class="tag">&lt;</span><span class="tag-name">filelist</span><span> </span><span class="attribute">dir</span><span>=</span><span class="attribute-value">&quot;config/db&quot;</span><span>              </span><span class="attribute">files</span><span>=</span><span class="attribute-value">&quot;sample.xml&quot;</span><span> </span><span class="tag">/&gt;</span><span>  </span></span></li>
    <li class="alt"><span>          <span class="tag">&lt;</span><span class="tag-name">filelist</span><span> </span><span class="attribute">dir</span><span>=</span><span class="attribute-value">&quot;config/db&quot;</span><span>              </span><span class="attribute">files</span><span>=</span><span class="attribute-value">&quot;end.xml&quot;</span><span> </span><span class="tag">/&gt;</span><span>  </span></span></li>
    <li class=""><span>      <span class="tag"><!--</span--><span class="tag-name">concat</span><span class="tag">&gt;</span><span>  </span></span></span></li>
    <li class="alt"><span>  <span class="tag"><!--</span--><span class="tag-name">target</span><span class="tag">&gt;</span><span>  </span></span></span></li>
</ol>
</div>
<br />
程序员需要自己手工配置好 config/db 目录下的两个数据源配置文件，datasource-dev.xml 用于开发，datasource-test.xml用于测试。<br />
<br />
（2）为每一个子系统设计一个 XXXTestCase 类，全部服务层测试类扩展这个类。XXXTestCase 类的主要任务是准备测试数据：<br />
<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"> </div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> SampleTestCase </span><span class="keyword">extends</span><span> BaseTestCase {  </span></span></li>
    <li class=""><span>  </span></li>
    <li class="alt"><span>    <span class="annotation">@BeforeMethod</span><span>  </span></span></li>
    <li class=""><span>    <span class="annotation">@Override</span><span>  </span></span></li>
    <li class="alt"><span>    <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> begin() {  </span></span></li>
    <li class=""><span>        <span class="keyword">super</span><span>.begin();  </span></span></li>
    <li class="alt"><span>         </span></li>
    <li class=""><span>        initTableData();  </span></li>
    <li class="alt"><span>    }  </span></li>
    <li class=""><span>     </span></li>
    <li class="alt"><span>    <span class="comment">/**</span> </span></li>
    <li class=""><span><span class="comment">     * 单元测试前让数据库表处于初始状态</span> </span></li>
    <li class="alt"><span><span class="comment">     */</span><span>  </span></span></li>
    <li class=""><span>    <span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> initTableData() {  </span></span></li>
    <li class="alt"><span>        exec(<span class="string">&quot;DELETE FROM Booking&quot;</span><span>);  </span></span></li>
    <li class=""><span>         </span></li>
    <li class="alt"><span>        exec(<span class="string">&quot;DELETE FROM Customer&quot;</span><span>);  </span></span></li>
    <li class=""><span>        exec(<span class="string">&quot;DELETE FROM Hotel&quot;</span><span>);  </span></span></li>
    <li class="alt"><span>        exec(<span class="string">&quot;DELETE FROM T_NextId&quot;</span><span>);  </span></span></li>
    <li class=""><span>    }  </span></li>
    <li class="alt"><span>  </span></li>
    <li class=""><span>    <span class="comment">/**</span> </span></li>
    <li class="alt"><span><span class="comment">     * 准备测试数据：Customer</span> </span></li>
    <li class=""><span><span class="comment">     */</span><span>  </span></span></li>
    <li class="alt"><span>    <span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> insert2User() {  </span></span></li>
    <li class=""><span>    exec(<span class="string">&quot;insert into Customer (username, password, name) values ('gavin', 'foobar', 'Gavin King')&quot;</span><span>);  </span></span></li>
    <li class="alt"><span>        exec(<span class="string">&quot;insert into Customer (username, password, name) values ('demo', 'demo', 'Demo User')&quot;</span><span>);  </span></span></li>
    <li class=""><span>    }  </span></li>
    <li class="alt"><span>  </span></li>
    <li class=""><span>    。。。  </span></li>
    <li class="alt"><span>}  </span></li>
</ol>
</div>
<br />
我采用了最灵活的一种方式来准备测试数据，就是SQL语句。由于Hibernate会生成数据库表之间的参照完整性约束， 因此，程序员在编写SQL脚本时应该考虑到这一点。<br />
<br />
（3）服务层的单元测试程序，由于继承了 XXXTestCase 类，可以集中于要测试的业务逻辑，例如：<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"> </div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> UserServiceTest </span><span class="keyword">extends</span><span> SampleTestCase {  </span></span></li>
    <li class=""><span>     </span></li>
    <li class="alt"><span>    <span class="keyword">private</span><span> UserService _userService;  </span></span></li>
    <li class=""><span>     </span></li>
    <li class="alt"><span>    <span class="annotation">@BeforeClass</span><span>  </span></span></li>
    <li class=""><span>    <span class="annotation">@Override</span><span>  </span></span></li>
    <li class="alt"><span>    <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> init() {  </span></span></li>
    <li class=""><span>        <span class="keyword">super</span><span>.init();  </span></span></li>
    <li class="alt"><span>         </span></li>
    <li class=""><span>        _userService = <span class="keyword">new</span><span> UserService();  </span></span></li>
    <li class="alt"><span>    }  </span></li>
    <li class=""><span>    </span></li>
    <li class="alt"><span>    <span class="annotation">@BeforeMethod</span><span>  </span></span></li>
    <li class=""><span>    <span class="annotation">@Override</span><span>  </span></span></li>
    <li class="alt"><span>    <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> begin() {  </span></span></li>
    <li class=""><span>        <span class="keyword">super</span><span>.begin();  </span></span></li>
    <li class="alt"><span>         </span></li>
    <li class=""><span>        _userService.setSession(session);  </span></li>
    <li class="alt"><span>    }  </span></li>
    <li class=""><span>     </span></li>
    <li class="alt"><span>    <span class="annotation">@Test</span><span>  </span></span></li>
    <li class=""><span>    <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> canLogin() {  </span></span></li>
    <li class="alt"><span>        insert2User();  </span></li>
    <li class=""><span>         </span></li>
    <li class="alt"><span>        <span class="keyword">assert</span><span> _userService.login(</span><span class="string">&quot;demo&quot;</span><span>, </span><span class="string">&quot;demo&quot;</span><span>);  </span></span></li>
    <li class=""><span>        <span class="keyword">assert</span><span> _userService.getUser().getUsername().equals(</span><span class="string">&quot;demo&quot;</span><span>);  </span></span></li>
    <li class="alt"><span>         </span></li>
    <li class=""><span>        <span class="keyword">assert</span><span> !_userService.login(</span><span class="string">&quot;demo&quot;</span><span>, </span><span class="string">&quot;demo2&quot;</span><span>);  </span></span></li>
    <li class="alt"><span>    }  </span></li>
    <li class=""><span>  </span></li>
    <li class="alt"><span>    。。。  </span></li>
    <li class=""><span>}  </span></li>
</ol>
</div>
<br />
<strong>4.单元测试编程时需要注意的问题</strong><br />
<br />
编写单元测试程序时，需要注意下列问题：<br />
<br />
（1）作为服务层设计的原则之一，禁止事务提交行为，因此，需要在单元测试方法中手工提交事务，如：<br />
<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"> </div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span> </span><span class="annotation">@Test</span><span>  </span></span></li>
    <li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> canChangePassword() {  </span></span></li>
    <li class="alt"><span>     insert2User();  </span></li>
    <li class=""><span>      </span></li>
    <li class="alt"><span>     User user = _userService.find(<span class="string">&quot;demo&quot;</span><span>);  </span></span></li>
    <li class=""><span>     _userService.setUser(user);  </span></li>
    <li class="alt"><span>      </span></li>
    <li class=""><span>     _userService.changePassword(<span class="string">&quot;demo2&quot;</span><span>);  </span></span></li>
    <li class="alt"><span>     session.flush(); <span class="comment">//使事务提交</span><span>  </span></span></li>
    <li class=""><span>     <span class="keyword">assert</span><span> _userService.find(</span><span class="string">&quot;demo&quot;</span><span>).getPassword().equals(</span><span class="string">&quot;demo2&quot;</span><span>);  </span></span></li>
    <li class="alt"><span>}     </span></li>
</ol>
</div>
<br />
（2）为了模拟Seam框架的对象注入，在服务层类中，需要为单元测试专门额外添加 setter 方法，例如：<br />
<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"> </div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="annotation">@BeforeMethod</span><span>  </span></span></li>
    <li class=""><span><span class="annotation">@Override</span><span>  </span></span></li>
    <li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">void</span><span> begin() {  </span></span></li>
    <li class=""><span>    <span class="keyword">super</span><span>.begin();  </span></span></li>
    <li class="alt"><span>     </span></li>
    <li class=""><span>    _hotelService.setSession(session); <span class="comment">//额外增加了setSession方法，专门用于单元测试</span><span>  </span></span></li>
    <li class="alt"><span>}  </span></li>
</ol>
</div>
<br />
<strong>5.结语</strong><br />
<br />
本项目所用的单元测试环境构建方法，是我对以往项目经验的基础上设计的，经过实践检验是可行的。<br />
<br />
这是本系列文章的最后一篇。下面是所有文章的完整列表：<br />
（1）<a href="http://fangzhouxing.javaeye.com/blog/144659">下载示例项目并安装运行</a><br />
（2）<a href="http://fangzhouxing.javaeye.com/blog/144777">建立Eclipse开发环境</a><br />
（3）<a href="http://fangzhouxing.javaeye.com/blog/145046">熟悉项目中与JSF相关内容</a><br />
（4）<a href="http://fangzhouxing.javaeye.com/blog/145965">重新认识JS</a><br />
（5）<a href="http://fangzhouxing.javaeye.com/blog/146169">ExtJS之表单(Form)</a><br />
（6）<a href="http://fangzhouxing.javaeye.com/blog/146424">ExtJS之布局(Layout)</a><br />
（7）<a href="http://fangzhouxing.javaeye.com/blog/146806">ExtJS之网格(Grid)</a><br />
（8）<a href="http://fangzhouxing.javaeye.com/blog/146966">Java后台和前台的通讯机制</a><br />
（9）<a href="http://fangzhouxing.javaeye.com/blog/147054">Seam框架简化Java开发</a><br />
（10）<a href="http://fangzhouxing.javaeye.com/blog/147125">分层架构设计</a><br />
（11）<a href="http://fangzhouxing.javaeye.com/blog/147539">安全性</a><br />
（12）单元测试<br />
<br />
          <br/>
          <span style="color:red;">
            <a href="http://fangzhouxing.javaeye.com/blog/147608#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><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>Tue, 11 Dec 2007 16:41:59 +0800</pubDate>
        <link>http://fangzhouxing.javaeye.com/blog/147608</link>
        <guid>http://fangzhouxing.javaeye.com/blog/147608</guid>
      </item>
      <item>
        <title>JBoss Seam (POJO without EJB) 后台 + ExtJS 前台完整例子（十一）</title>
        <author>fangzhouxing</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fangzhouxing.javaeye.com">fangzhouxing</a>&nbsp;
          链接：<a href="http://fangzhouxing.javaeye.com/blog/147539" style="color:red;">http://fangzhouxing.javaeye.com/blog/147539</a>&nbsp;
          发表时间: 2007年12月11日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h1>JBoss Seam (POJO without EJB) 后台 + ExtJS 前台完整例子（十一）</h1>
<br />
<strong>1.引言</strong><br />
<br />
随着internet的发展，业务过程、事务以及企业信息需要向更广泛的用户群公开。这一变化给应用程序和基础设施带来了重大的影响，其中最明显的影响就是应用程序安全方面。Seam框架提供了可选的安全性API，可以实现身份验证（authentication）和授权（authorization）功能。<br />
<br />
本文主要介绍项目中安全性方面的初步实践，更深入的内容有待于进一步的开发经验的积累。<br />
<br />
<strong>2.基本的安全性需求</strong><br />
<br />
本项目要求实现下列基本的安全性需求：<br />
（1）可以让用户没有限制地使用登录页面和注册新用户页面。<br />
（2）其它任何页面，必须先登录才能使用。<br />
（3）远程外观类中通过Seam Remoting暴露的后台服务，除登录和新建用户外，只能被已经登录的用户调用。<br />
（4）通过Servlet暴露的服务，只能被已经登录的用户调用。<br />
<br />
<strong>3. 扩展 Identity 类</strong><br />
<br />
Seam框架内建了Identity组件类，提供安全性管理功能。本项目通过 com.divo.core.misc.ExtendedIdentity 扩展了Identity 类：<br />
<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"> </div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="annotation">@Name</span><span>(</span><span class="string">&quot;org.jboss.seam.security.identity&quot;</span><span>)  </span></span></li>
    <li class=""><span><span class="annotation">@Scope</span><span>(SESSION)  </span></span></li>
    <li class="alt"><span><span class="annotation">@Install</span><span>(precedence = APPLICATION)  </span></span></li>
    <li class=""><span><span class="annotation">@BypassInterceptors</span><span>  </span></span></li>
    <li class="alt"><span><span class="annotation">@Startup</span><span>  </span></span></li>
    <li class=""><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> ExtendedIdentity </span><span class="keyword">extends</span><span> Identity {  </span></span></li>
    <li class="alt"><span>  </span></li>
    <li class=""><span>    <span class="annotation">@Override</span><span>  </span></span></li>
    <li class="alt"><span>    <span class="keyword">public</span><span> </span><span class="keyword">boolean</span><span> hasPermission(String name, String action, Object... arg) {  </span></span></li>
    <li class=""><span>    <span class="keyword">return</span><span> </span><span class="keyword">true</span><span>;  </span></span></li>
    <li class="alt"><span>    }  </span></li>
    <li class=""><span>  </span></li>
    <li class="alt"><span>    <span class="annotation">@Override</span><span>  </span></span></li>
    <li class=""><span>    <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> checkPermission(String name, String action, Object... arg) {  </span></span></li>
    <li class="alt"><span>    <span class="keyword">if</span><span> (!isLoggedIn()) {  </span></span></li>
    <li class=""><span>        Events.instance().raiseEvent(<span class="string">&quot;org.jboss.seam.notLoggedIn&quot;</span><span>);  </span></span></li>
    <li class="alt"><span>        <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> NotLoggedInException();  </span></span></li>
    <li class=""><span>    }  </span></li>
    <li class="alt"><span>    }  </span></li>
    <li class=""><span>  </span></li>
    <li class="alt"><span>    <span class="annotation">@Override</span><span>  </span></span></li>
    <li class=""><span>    <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> checkRestriction(String expr) {  </span></span></li>
    <li class="alt"><span>    <span class="keyword">if</span><span> (!isLoggedIn()) {  </span></span></li>
    <li class=""><span>        Events.instance().raiseEvent(<span class="string">&quot;org.jboss.seam.notLoggedIn&quot;</span><span>);  </span></span></li>
    <li class="alt"><span>        <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> NotLoggedInException();  </span></span></li>
    <li class=""><span>    }  </span></li>
    <li class="alt"><span>    }  </span></li>
    <li class=""><span>}  </span></li>
</ol>
</div>
<br />
如<a href="http://fangzhouxing.javaeye.com/blog/147054">这篇文章</a>所述，通过无依赖扩展，ExtendedIdentity 将代替内建的 Identity 组件。<br />
<br />
<strong>4. 页面访问权限控制</strong><br />
<br />
页面访问权限控制在 page.xml 中设置：<br />
<div class="code_title">xml 代码</div>
<div class="dp-highlighter">
<div class="bar"> </div>
<ol class="dp-xml" start="1">
    <li class="alt"><span><span class="tag">&lt;</span><span class="tag-name">exception</span><span> </span><span class="attribute">class</span><span>=</span><span class="attribute-value">&quot;org.jboss.seam.security.NotLoggedInException&quot;</span><span class="tag">&gt;</span><span>  </span></span></li>
    <li class=""><span>      <span class="tag">&lt;</span><span class="tag-name">redirect</span><span> </span><span class="attribute">view-id</span><span>=</span><span class="attribute-value">&quot;/app/home.xhtml&quot;</span><span class="tag">&gt;</span><span>  </span></span></li>
    <li class="alt"><span>      <span class="tag"><!--</span--><span class="tag-name">redirect</span><span class="tag">&gt;</span><span>  </span></span></span></li>
    <li class=""><span>  <span class="tag"><!--</span--><span class="tag-name">exception</span><span class="tag">&gt;</span><span>  </span></span></span></li>
    <li class="alt"><span>  </span></li>
    <li class=""><span>  <span class="tag">&lt;</span><span class="tag-name">page</span><span> </span><span class="attribute">view-id</span><span>=</span><span class="attribute-value">&quot;/app/sample/*&quot;</span><span class="tag">&gt;</span><span>  </span></span></li>
    <li class="alt"><span>  <span class="tag">&lt;</span><span class="tag-name">restrict</span><span class="tag">/&gt;</span><span>  </span></span></li>
    <li class=""><span>  <span class="tag"><!--</span--><span class="tag-name">page</span><span class="tag">&gt;</span><span>  </span></span></span></li>
</ol>
</div>
<br />
<br />
其中的 exception 配置，使得异常 NotLoggedInException 抛出时，会自动跳转到登录首页。而 page 属性配置，使得用户没有登录而试图访问 /app/sample 目录（及其子目录）下的页面时，将受到限制。<br />
<br />
显然，用户访问 /app/sample 目录以外的页面时，将不受限制。<br />
<br />
所谓&ldquo;受到限制&rdquo;，实际上就是Seam框架会自动调用 ExtendedIdentity 组件的 checkRestriction 方法。如果判断用户没有登录，则抛出 NotLoggedInException 异常。<br />
<br />
<strong>5. 登录功能与Seam集成</strong><br />
<br />
应用程序通过用户名和密码让合法用户登录，为了利用Seam框架提供的安全性设施，需要与Seam集成。<br />
<br />
本项目的集成方法如下：<br />
<br />
第1步：配置 components.xml<br />
<br />
<div class="code_title">xml 代码</div>
<div class="dp-highlighter">
<div class="bar"> </div>
<ol class="dp-xml" start="1">
    <li class="alt"><span><span class="tag">&lt;</span><span class="tag-name">security:identity</span><span> </span><span class="attribute">authenticate-method</span><span>=</span><span class="attribute-value">&quot;#{userService.authenticate}&quot;</span><span class="tag">/&gt;</span><span>  </span></span></li>
</ol>
</div>
<br />
第2步：在 UserService 类中，按通常方法实现 login 服务。<br />
<br />
第3步：登录验证通过后，在 Identity 组件中填入当前登录用户的用户名和密码，并调用其 login 方法：<br />
<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<ol class="dp-j" start="1">
    <li class="alt"><span><span>identity.setUsername(name);  </span></span></li>
    <li class=""><span>  identity.setPassword(password);  </span></li>
    <li class="alt"><span>  identity.login();  </span></li>
</ol>
</div>
<br />
<br />
第4步：按照 components.xml 中的配置，在 UserService 类在实现 authenticate 方法。<br />
<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"> </div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">boolean</span><span> authenticate() {  </span></span></li>
    <li class=""><span>    <span class="keyword">return</span><span> </span><span class="keyword">true</span><span>;  </span></span></li>
    <li class="alt"><span>}  </span></li>
</ol>
</div>
<br />
因为应用程序的登录验证已经在 login 方法中实现，所以 authenticate 方法仅仅是走走形式而已。<br />
<br />
第5步：在 UserService 类中实现注销功能：<br />
<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<ol class="dp-j" start="1">
    <li class="alt"><span><span>identity.logout();  </span></span></li>
</ol>
</div>
<br />
<br />
<strong>6. 使用@Restrict元注解</strong><br />
<br />
@Restrict 元注解可以应用到类，也可以应用到类方法。@Restrict 元注解将引导 Seam 框架去执行 <br />
Identity.checkRestriction() 方法。<br />
<br />
本项目中，要求在服务层组件添加 @Restrict 元注解。因为远程外观类和Servlet类都必须通过服务层<br />
组件实现具体的功能，因此同时满足了通过Seam Remoting和Servlet暴露的后台服务对安全性的要求。<br />
<br />
<strong>7. 进一步的扩展</strong><br />
<br />
本项目实现的安全性还是初步的，实际项目往往会考虑按角色对用户进行分组。每个角色规定相应的权限。<br />
通过进一步扩展 ExtendedIdentity.checkRestriction() 的功能，可以实现基于角色的安全性控制。<br />
<br />
<strong>8. 结语</strong><br />
<br />
Seam框架提供的安全性API和机制细致而周到，简化了开发，值得进行深入的学习和研究。<br />
<br />
附：下面是本系列所有文章的完整列表：<br />
（1）<a href="http://fangzhouxing.javaeye.com/blog/144659">下载示例项目并安装运行</a><br />
（2）<a href="http://fangzhouxing.javaeye.com/blog/144777">建立Eclipse开发环境</a><br />
（3）<a href="http://fangzhouxing.javaeye.com/blog/145046">熟悉项目中与JSF相关内容</a><br />
（4）<a href="http://fangzhouxing.javaeye.com/blog/145965">重新认识JS</a><br />
（5）<a href="http://fangzhouxing.javaeye.com/blog/146169">ExtJS之表单(Form)</a><br />
（6）<a href="http://fangzhouxing.javaeye.com/blog/146424">ExtJS之布局(Layout)</a><br />
（7）<a href="http://fangzhouxing.javaeye.com/blog/146806">ExtJS之网格(Grid)</a><br />
（8）<a href="http://fangzhouxing.javaeye.com/blog/146966">Java后台和前台的通讯机制</a><br />
（9）<a href="http://fangzhouxing.javaeye.com/blog/147054">Seam框架简化Java开发</a><br />
（10）<a href="http://fangzhouxing.javaeye.com/blog/147125">分层架构设计</a><br />
（11）<a href="http://fangzhouxing.javaeye.com/blog/147539">安全性</a><br />
（12）<a href="http://fangzhouxing.javaeye.com/blog/147539">单元测试</a><br />
<br />
          <br/>
          <span style="color:red;">
            <a href="http://fangzhouxing.javaeye.com/blog/147539#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><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/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 11 Dec 2007 13:28:37 +0800</pubDate>
        <link>http://fangzhouxing.javaeye.com/blog/147539</link>
        <guid>http://fangzhouxing.javaeye.com/blog/147539</guid>
      </item>
      <item>
        <title>JBoss Seam (POJO without EJB) 后台 + ExtJS 前台完整例子（十）</title>
        <author>fangzhouxing</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fangzhouxing.javaeye.com">fangzhouxing</a>&nbsp;
          链接：<a href="http://fangzhouxing.javaeye.com/blog/147125" style="color:red;">http://fangzhouxing.javaeye.com/blog/147125</a>&nbsp;
          发表时间: 2007年12月09日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h1>JBoss Seam (POJO without EJB) 后台 + ExtJS 前台完整例子（十）</h1>
<br />
<strong>1.引言</strong><br />
<br />
分层是分解复杂软件系统最常用的技术。当用分层的观点来设计系统时，各个子系统的形式类似&ldquo;多层蛋糕&rdquo;。每一层都依托在其下层之上，上层使用了下层定义的各种服务，而下层对上层一无所知。<br />
<br />
分层设计的难点是决定建立哪些层次，以及每一层的职责是什么。本文介绍项目中采用的分层设计思路，最后说明了为何要强调使用POJO without EJB的设计。<br />
<br />
需要特别说明的是，本文的很多想法和术语，均来自Martin Fowler大师的《企业应用架构模式》（2004年7月版）一书。如果你还没有阅读过这本书，可能会对本文所用的很多术语感到陌生。<br />
<br />
<strong>2.分层概述</strong><br />
<br />
本项目采用的分层技术将后台系统划分为下列三层：<br />
（1）远程外观层(Remote Facade Layer)<br />
（2）服务层(Service Layer)<br />
（3）领域模型层(Domain Model Layer)<br />
<br />
服务层和领域模型层实际上都属于&ldquo;领域层&rdquo;。org.jboss.seam.example.divo.domain 包中的类构成了最低级的领域模型层。这些类是Hibernate的实体类，但它们可以在各层之间传递数据，从而消除了传统的DTO(数据传输对象）。实体类中只有数据，不包含业务逻辑。<br />
<br />
服务层是从领域层中独立出来的，它用Martin Fowler所谓的&ldquo;操作脚本方法&rdquo;实现。服务层可以直接通过JDBC操作数据库，也可以通过Hibernate和实体类操作数据库。服务层的所有类在org.jboss.seam.example.divo.service 包中，类名表示为 XXXService.java。<br />
<br />
远程外观层是在服务层之上添加的。通过远程外观层，为细粒度对象提供粗粒度的外观来改进网络上的效率。这一点在事务处理设计上体现得特别明显。我们总是假设远程外观层的一个方法是一个完整的事务，而服务层中的一个方法是某个事务的一部分。<br />
<br />
<strong>3.用Seam Remoting实现远程外观</strong><br />
<br />
Seam Remoting是前后台通讯的主要机制之一。一般情况下，系统划分为若干&ldquo;子系统&rdquo;，一个子系统设计一个远程外观类，被客户端通过 Seam Remoting 调用，类名表示为 XXXFacade.java。<br />
<br />
在本项目中，org.jboss.seam.example.divo.SampleFacade.java 就是一个远程外观类。SampleFacade 中一般不实现特定的业务逻辑，它把具体的操作交给服务层进行处理。<br />
<br />
注意 SampleFacade 的@Transactional元注解：<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"> </div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="annotation">@WebRemote</span><span>  </span></span></li>
    <li class=""><span><span class="annotation">@Transactional</span><span>  </span></span></li>
    <li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">void</span><span> deleteBooking(</span><span class="keyword">int</span><span> id) {  </span></span></li>
    <li class=""><span>    bookingService.delete(id);  </span></li>
    <li class="alt"><span>}  </span></li>
</ol>
</div>
<br />
按照Seam框架的规定，没有@Transactional元注解的方法，表示支持事务处理，即相当于使用了@Transactional(SUPPORTS)元注解，只可以参与某个事务。而使用了不带参数的@Transactional，则表示<br />
@Transactional(REQUIRED)，它会在方法执行完毕后自动提交事务。<br />
<br />
<strong>4.用Servlet作为远程外观</strong><br />
<br />
JSON是前后台通讯的另外一种机制。需要通过Servlet才能实现JSON数据的传递。在本项目中，Servlet处于和远程外观类相同的地位，可以把它看成是另外的一种远程外观。<br />
<br />
建议一个子系统只设计一个Servlet，通过action传递参数区分不同的客户端请求。SampleServlet 就是这样做的：<br />
<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"> </div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="annotation">@Override</span><span>  </span></span></li>
    <li class=""><span><span class="keyword">public</span><span> </span><span class="keyword">void</span><span> doGet(HttpServletRequest request, HttpServletResponse response)  </span></span></li>
    <li class="alt"><span>        <span class="keyword">throws</span><span> ServletException, IOException {  </span></span></li>
    <li class=""><span>    createHotelService();  </span></li>
    <li class="alt"><span>    createBookingService();  </span></li>
    <li class=""><span>  </span></li>
    <li class="alt"><span>    String action = request.getParameter(<span class="string">&quot;action&quot;</span><span>);  </span></span></li>
    <li class=""><span>     </span></li>
    <li class="alt"><span>    <span class="keyword">if</span><span> (action.equals(</span><span class="string">&quot;hotelList&quot;</span><span>))  </span></span></li>
    <li class=""><span>        runHotelList(request, response);  </span></li>
    <li class="alt"><span>     </span></li>
    <li class=""><span>    <span class="keyword">if</span><span> (action.equals(</span><span class="string">&quot;bookingList&quot;</span><span>))  </span></span></li>
    <li class="alt"><span>        runBookingList(request, response);  </span></li>
    <li class=""><span>  </span></li>
    <li class="alt"><span>}  </span></li>
</ol>
</div>
<br />
与远程外观类相同，Servlet中不要实现特定的业务逻辑，应把具体的操作交给服务层进行处理。<br />
<br />
<strong>5.服务层</strong><br />
<br />
一般情况下，针对某个实体实现一个服务类，但也可以针对某种特定的用途设计服务类。<br />
<br />
服务类设计应该遵循下列原则：<br />
（1）使用@AutoCreate元注解，使服务类被注入时自动创建对象实例。<br />
（2）通过自动注入的 org.hibernate.Session 对象访问和操作 Hibernate 实体类，实现业务逻辑。<br />
（3）如果要直接用JDBC访问数据库，可以从org.hibernate.Session 对象中直接得到数据库连接，例如：<br />
<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"> </div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="comment">/**</span> </span></li>
    <li class=""><span><span class="comment"> * 执行SQL语句(不返回结果)</span> </span></li>
    <li class="alt"><span><span class="comment"> */</span><span>  </span></span></li>
    <li class=""><span><span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> exec(String sql) {  </span></span></li>
    <li class="alt"><span>java.sql.PreparedStatement prepStatement = <span class="keyword">null</span><span>;  </span></span></li>
    <li class=""><span>  </span></li>
    <li class="alt"><span>Connection conn = <span class="keyword">null</span><span>;  </span></span></li>
    <li class=""><span><span class="keyword">try</span><span> {  </span></span></li>
    <li class="alt"><span>    conn = hs.connection();  </span></li>
    <li class=""><span>  </span></li>
    <li class="alt"><span>    prepStatement = conn.prepareStatement(sql);  </span></li>
    <li class=""><span>    prepStatement.executeUpdate();  </span></li>
    <li class="alt"><span>  </span></li>
    <li class=""><span>} <span class="keyword">catch</span><span> (SQLException e) {  </span></span></li>
    <li class="alt"><span>    e.printStackTrace();  </span></li>
    <li class=""><span>} <span class="keyword">finally</span><span> {  </span></span></li>
    <li class="alt"><span>    <span class="keyword">if</span><span> (conn != </span><span class="keyword">null</span><span>)  </span></span></li>
    <li class=""><span>    <span class="keyword">try</span><span> {  </span></span></li>
    <li class="alt"><span>        conn.close();  </span></li>
    <li class=""><span>    } <span class="keyword">catch</span><span> (SQLException e) {  </span></span></li>
    <li class="alt"><span>        e.printStackTrace();  </span></li>
    <li class=""><span>    }  </span></li>
    <li class="alt"><span>}  </span></li>
    <li class=""><span>}  </span></li>
</ol>
</div>
<strong><br />
6.领域模型层</strong><br />
<br />
为了简化设计，直接使用Hibernate作为构建和持久化领域模型的基础。Hibernate数据源在<br />
hibernate.cfg.xml 中进行配置。<br />
<br />
基于Hibernate的实体类的设计应该遵循下列原则：<br />
（1）尽量不用org.hibernate.validator包中的验证规则，相关业务逻辑改在服务层实现。<br />
（2）避免使用序列自动生成Id, 采用下面的表生成Id方法：<br />
<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"> </div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="annotation">@Id</span><span>  </span></span></li>
    <li class=""><span><span class="annotation">@GeneratedValue</span><span>(strategy = GenerationType.TABLE, generator=</span><span class="string">&quot;nextid&quot;</span><span>)  </span></span></li>
    <li class="alt"><span><span class="annotation">@TableGenerator</span><span>(name=</span><span class="string">&quot;nextid&quot;</span><span>, table=</span><span class="string">&quot;T_NextId&quot;</span><span>, allocationSize=</span><span class="number">1</span><span>)  </span></span></li>
    <li class=""><span><span class="keyword">public</span><span> </span><span class="keyword">int</span><span> getId()  </span></span></li>
    <li class="alt"><span>{  </span></li>
    <li class=""><span>   <span class="keyword">return</span><span> id;  </span></span></li>
    <li class="alt"><span>}  </span></li>
    <li class=""><span><span class="keyword">public</span><span> </span><span class="keyword">void</span><span> setId(</span><span class="keyword">int</span><span> id)  </span></span></li>
    <li class="alt"><span>{  </span></li>
    <li class=""><span>   <span class="keyword">this</span><span>.id = id;  </span></span></li>
    <li class="alt"><span>}  </span></li>
</ol>
</div>
<br />
<strong>7. POJO without EJB</strong><br />
<br />
尽管EJB3做出了重大的改进，但是，对于大量的应用程序来说，仍然存在更易使用且更好的替代方案。《POJOs In Action》一书的作者认为在下面两种情况下，才需要使用EJB:<br />
（1）使用由远程客户端发起的分布式事务的应用程序。<br />
（2）极度消息导向，需要大量消息驱动bean的应用程序。<br />
<br />
对于访问量大、并发用户多的大型网站，有人认为应该<a href="http://www.javaeye.com/topic/40335">使用EJB</a> ，才能保证系统的可扩展行和性能。实际上，采用POJO without EJB设计也是完全可行的，网站的<a href="http://www.toplee.com/blog/71.html">性能瓶颈</a>往往发生在数据库访问速度上。<br />
<br />
在Seam框架下，使用POJO without EJB设计后，对集群(clustering)和故障恢复(failover)的实现有些什么<br />
影响，有关文献似乎没有明确的说明。<br />
<br />
<strong>8.结语</strong><br />
<br />
分层技术通过明确各层的职责，使系统的整体设计简洁而完整。Seam框架的组件模型极大地简化了分层设计的实现。有人可能对本项目采用的POJO without EJB设计不能认同，但其提高开发效率的效果是非常明显的。<br />
<br />
附：下面是本系列所有文章的完整列表：<br />
（1）<a href="http://fangzhouxing.javaeye.com/blog/144659">下载示例项目并安装运行</a><br />
（2）<a href="http://fangzhouxing.javaeye.com/blog/144777">建立Eclipse开发环境</a><br />
（3）<a href="http://fangzhouxing.javaeye.com/blog/145046">熟悉项目中与JSF相关内容</a><br />
（4）<a href="http://fangzhouxing.javaeye.com/blog/145965">重新认识JS</a><br />
（5）<a href="http://fangzhouxing.javaeye.com/blog/146169">ExtJS之表单(Form)</a><br />
（6）<a href="http://fangzhouxing.javaeye.com/blog/146424">ExtJS之布局(Layout)</a><br />
（7）<a href="http://fangzhouxing.javaeye.com/blog/146806">ExtJS之网格(Grid)</a><br />
（8）<a href="http://fangzhouxing.javaeye.com/blog/146966">Java后台和前台的通讯机制</a><br />
（9）<a href="http://fangzhouxing.javaeye.com/blog/147054">Seam框架简化Java开发</a><br />
（10）<a href="http://fangzhouxing.javaeye.com/blog/147125">分层架构设计</a><br />
（11）<a href="http://fangzhouxing.javaeye.com/blog/147539">安全性</a><br />
（12）<a href="http://fangzhouxing.javaeye.com/blog/147539">单元测试</a>
          <br/>
          <span style="color:red;">
            <a href="http://fangzhouxing.javaeye.com/blog/147125#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></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 09 Dec 2007 22:41:43 +0800</pubDate>
        <link>http://fangzhouxing.javaeye.com/blog/147125</link>
        <guid>http://fangzhouxing.javaeye.com/blog/147125</guid>
      </item>
      <item>
        <title>JBoss Seam (POJO without EJB) 后台 + ExtJS 前台完整例子（九）</title>
        <author>fangzhouxing</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fangzhouxing.javaeye.com">fangzhouxing</a>&nbsp;
          链接：<a href="http://fangzhouxing.javaeye.com/blog/147054" style="color:red;">http://fangzhouxing.javaeye.com/blog/147054</a>&nbsp;
          发表时间: 2007年12月09日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h1>JBoss Seam (POJO without EJB) 后台 + ExtJS 前台完整例子（九）</h1>
<br />
<strong>1.引言</strong><br />
<br />
在2007年初，接触到了RubyOnRails，为其开发的快捷和方便所折服。反观用了多年的Java技术，则很难找到能与之抗衡的新框架。难怪有人要超越java（<a href="http://www.oreilly.com/catalog/beyondjava/">Beyond Java</a>）了。<br />
<br />
<a href="http://www.springframework.org/">Spring </a> 曾经因为倡导无EJB的J2EE企业级开发，近几年来得到了广泛的关注和应用。JBoss Seam（本文下面简称为Seam)的出现，被认为和Spring框架存在着不同技术架构的竞争关系。对它们之间的关系出现了很多的<a href="http://zeroliu.blogdriver.com/zeroliu/1233377.html ">争论与取舍</a>。这也许是一件好事，从另一面反映出了Java 社区的活力。<br />
<br />
Seam的很多概念比较新，所以本文首先罗列了一些有价值的资源。然后以本项目的实践为基础，说明Seam从哪些方面简化了Java开发。<br />
<br />
<strong>2. 认识Seam</strong><br />
<br />
Seam 2.0是2007年11月发布的，系统完整的中文资料可能还难以找到，你应该从阅读其发行包中的参考手册开始。不过，已经有人在<a href="http://yulimin.javaeye.com/blog/120769">组织翻译</a>Seam的参考手册，相信不久就会发表。<br />
<br />
今年出版的《<a href="http://www.amazon.com/JBoss-Seam-Simplicity-Beyond-Prentice/dp/0131347969">JBoss seam : simplicity and power beyond Java EE</a>》是必须阅读的一本好书。<br />
<br />
从全局域管理的角度来认识Seam，我认为抓住了Seam的核心概念，让人有茅塞顿开的感觉。感谢zaya的这篇好<a href="http://www.javaeye.com/topic/137567?page=1 ">文章</a>。    <br />
<br />
<strong>3. 元注解代替XML配置文件</strong><br />
<br />
每个Java开发人员对XML配置文件都不会陌生. 随着应用规模的扩大, XML配置文件的内容会随之膨胀, 带来管理上的困难. Seam用元注解(meta annotation)代替了XML配置文件。<br />
<br />
例子1:<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"> </div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="annotation">@Restrict</span><span>  </span></span></li>
    <li class=""><span><span class="annotation">@Name</span><span>(</span><span class="string">&quot;hotelService&quot;</span><span>)  </span></span></li>
    <li class="alt"><span><span class="annotation">@AutoCreate</span><span>  </span></span></li>
    <li class=""><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> HotelService </span><span class="keyword">extends</span><span> BaseService {  </span></span></li>
    <li class="alt"><span>。。。  </span></li>
</ol>
</div>
<br />
例子2：<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"> </div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="annotation">@Entity</span><span>  </span></span></li>
    <li class=""><span><span class="annotation">@Name</span><span>(</span><span class="string">&quot;user&quot;</span><span>)  </span></span></li>
    <li class="alt"><span><span class="annotation">@Scope</span><span>(SESSION)  </span></span></li>
    <li class=""><span><span class="annotation">@Table</span><span>(name=</span><span class="string">&quot;Customer&quot;</span><span>)  </span></span></li>
    <li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> User </span><span class="keyword">implements</span><span> Serializable  </span></span></li>
    <li class=""><span>{  </span></li>
    <li class="alt"><span>   。。。  </span></li>
    <li class=""><span>   <span class="annotation">@Id</span><span>  </span></span></li>
    <li class="alt"><span>   <span class="keyword">public</span><span> String getUsername()  </span></span></li>
    <li class=""><span>   {  </span></li>
    <li class="alt"><span>      <span class="keyword">return</span><span> username;  </span></span></li>
    <li class=""><span>   }  </span></li>
</ol>
</div>
<br />
<strong>4. 对象的创建与应用代码分离</strong><br />
<br />
应用不再由new关键字或者Class.forName()来创建（组件的）对象。我们来对比一下。<br />
<br />
在没有使用Seam框架的程序中，外观类或控制器类中，要调用服务类的方法，必须先创建服务类的实例，这样做：<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"> </div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="keyword">private</span><span> UserService _userService = </span><span class="keyword">null</span><span>;  </span></span></li>
    <li class=""><span>  </span></li>
    <li class="alt"><span><span class="keyword">private</span><span> </span><span class="keyword">void</span><span> createUserService() {  </span></span></li>
    <li class=""><span><span class="keyword">if</span><span> (_userService == </span><span class="keyword">null</span><span>)  </span></span></li>
    <li class="alt"><span>    _userService = <span class="keyword">new</span><span> UserService();  </span></span></li>
    <li class=""><span>}  </span></li>
    <li class="alt"><span>  </span></li>
    <li class=""><span><span class="keyword">public</span><span> FormValidateResult changePassword(</span><span class="keyword">int</span><span> userId, String currentPassword, String newPassword, String newPassword2, HttpSession session) {  </span></span></li>
    <li class="alt"><span>createUserService();  </span></li>
    <li class=""><span><span class="keyword">return</span><span> _userService.changePassword(userId, currentPassword, newPassword, newPassword2, session);  </span></span></li>
    <li class="alt"><span>}  </span></li>
</ol>
</div>
<br />
用了Seam框架后，我们可以这样做：<br />
<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"> </div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="annotation">@In</span><span> </span><span class="keyword">private</span><span> UserService userService;  </span></span></li>
    <li class=""><span>  </span></li>
    <li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">void</span><span> changePassword(String newPassword) {  </span></span></li>
    <li class=""><span>    userService.changePassword(newPassword);  </span></li>
    <li class="alt"><span>}  </span></li>
</ol>
</div>
<br />
借助@In元注解，我们需要的服务类对象（userService），Seam框架会自动创建并送来。<br />
<br />
<strong>5. 类即对象</strong><br />
<br />
这一点在<a href="http://www.javaeye.com/topic/137567?page=1 ">zaya文章</a>中有很精彩的描述。动态类型语言（如Ruby、JavaScript等)的特点就是模糊了对象和类之间的区别。对于开发人员来说，在Seam框架下编程，因为总是在与已经实例化的对象打交道，所以给人的感觉好像总是在调用类中的静态方法。<br />
<br />
<strong>6. 层之间不再需要用接口来连接</strong><br />
<br />
用接口(interface）来隔离不同层，被认为是提高软件可维护性的好的做法。但是，在大多数情况下，它所带来的好处却远远没有给开发效率的影响来得大。<br />
<br />
如果你用POJO作为Seam的组件，那么你无需编写相应的接口就能直接访问不同层的组件。<br />
<br />
<strong>7. 无依赖扩展</strong><br />
<br />
这一点在<a href="http://www.javaeye.com/topic/137567?page=1 ">zaya文章</a>中也有很精彩的描述。本项目中的 com.divo.core.misc.ExtendedIdentity 类就是一个很好的例子:<br />
<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"> </div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="annotation">@Name</span><span>(</span><span class="string">&quot;org.jboss.seam.security.identity&quot;</span><span>)  </span></span></li>
    <li class=""><span><span class="annotation">@Scope</span><span>(SESSION)  </span></span></li>
    <li class="alt"><span><span class="annotation">@Install</span><span>(precedence = APPLICATION)  </span></span></li>
    <li class=""><span><span class="annotation">@BypassInterceptors</span><span>  </span></span></li>
    <li class="alt"><span><span class="annotation">@Startup</span><span>  </span></span></li>
    <li class=""><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> ExtendedIdentity </span><span class="keyword">extends</span><span> Identity {  </span></span></li>
    <li class="alt"><span>。。。  </span></li>
</ol>
</div>
<br />
通过 @Install(precedence = APPLICATION) 元注解，能自动用 ExtendedIdentity 类替换掉 Seam 框架内建的 Identity 组件。<br />
<br />
<strong>8. 双向注入</strong><br />
<br />
在操作当前登录用户信息时，双向注入给编程带来的好处是很明显的。用户登录成功后，传统的做法需要自己编程把用户信息存入 session：<br />
<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"> </div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="keyword">public</span><span> FormValidateResult login(String loginName, String password, </span><span class="keyword">boolean</span><span> remember, HttpSession session, HttpServletResponse res) {  </span></span></li>
    <li class=""><span>...  </span></li>
    <li class="alt"><span>  </span></li>
    <li class=""><span>      CurrentLogin myLogin = CurrentLogin.newInstance(userId,userName,loginName);  </span></li>
    <li class="alt"><span>      session.setAttribute(CurrentLogin.LOGIN_KEY, myLogin);  </span></li>
</ol>
</div>
<br />
在需要当前登录用户信息时，再从session中取出：<br />
<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<ol class="dp-j" start="1">
    <li class="alt"><span><span>CurrentLogin myLogin = (CurrentLogin) session.getAttribute(CurrentLogin.LOGIN_KEY);  </span></span></li>
</ol>
</div>
<br />
用Seam框架编程，相同的功能这样实现（参见UserService.java类）：<br />
<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar"> </div>
<ol class="dp-j" start="1">
    <li class="alt"><span><span class="annotation">@In</span><span>(required = </span><span class="keyword">false</span><span>) User user;  </span></span></li>
    <li class=""><span>  </span></li>
    <li class="alt"><span><span class="annotation">@Out</span><span>(required = </span><span class="keyword">false</span><span>, scope = SESSION)  </span></span></li>
    <li class=""><span><span class="keyword">public</span><span> User getUser() {  </span></span></li>
    <li class="alt"><span>    <span class="keyword">return</span><span> </span><span class="keyword">this</span><span>.user;  </span></span></li>
    <li class=""><span>}  </span></li>
</ol>
</div>
<br />
通过注出(@Out)元注解，使得登录成功后，无需写任何代码，就能自动将当前登录用户信息保存到会话域。而修改用户密码时，我们也不用写任何代码，Seam框架自动从会话域取出了当前登录用户对象给我们用。<br />
<br />
<strong>9. 对话域</strong><br />
<br />
Seam框架为了解决会话域膨胀问题，引入了一个新的域，即对话域（conversation scope)。从现有设计来看，它主要是为了解决跨多个页面的请求的状态问题。客户端改用ExtJS后，跨多个页面的请求显然已经消失。<br />
<br />
那么对话域是否还有用呢？从目前的实践来看，还不好下什么结论。所以我在这里先把问题提出来吧。<br />
<br />
<strong>10. 安全性</strong><br />
<br />
Seam框架对安全性的考虑非常细致周到，本系列文章将有专门的一篇加以介绍。<br />
<br />
<strong>11.不强制使用特定的架构</strong><br />
<br />
应用的规模和要求会有很多差异，用Seam框架可以选择使用EJB，也可以使用POJO without EJB。使用POJO后，仍然可以获得Seam框架提供的各种组件特性。<br />
<br />
本项目就使用POJO without EJB这种轻量级的架构方案，并且设计了外观-服务分层架构，详细内容请参见本系列的下一篇文章。<br />
<br />
<strong>12.结语</strong><br />
<br />
本人对Seam框架的学习和实践还是初步的，体会还比较粗浅。但是，Seam框架对Java开发的简化，的确是走出了很大的一步。<br />
<br />
附：下面是本系列所有文章的完整列表：<br />
（1）<a href="http://fangzhouxing.javaeye.com/blog/144659">下载示例项目并安装运行</a><br />
（2）<a href="http://fangzhouxing.javaeye.com/blog/144777">建立Eclipse开发环境</a><br />
（3）<a href="http://fangzhouxing.javaeye.com/blog/145046">熟悉项目中与JSF相关内容</a><br />
（4）<a href="http://fangzhouxing.javaeye.com/blog/145965">重新认识JS</a><br />
（5）<a href="http://fangzhouxing.javaeye.com/blog/146169">ExtJS之表单(Form)</a><br />
（6）<a href="http://fangzhouxing.javaeye.com/blog/146424">ExtJS之布局(Layout)</a><br />
（7）<a href="http://fangzhouxing.javaeye.com/blog/146806">ExtJS之网格(Grid)</a><br />
（8）<a href="http://fangzhouxing.javaeye.com/blog/146966">Java后台和前台的通讯机制</a><br />
（9）<a href="http://fangzhouxing.javaeye.com/blog/147054">Seam框架简化Java开发</a><br />
（10）<a href="http://fangzhouxing.javaeye.com/blog/147125">分层架构设计</a><br />
（11）<a href="http://fangzhouxing.javaeye.com/blog/147539">安全性</a><br />
（12）<a href="http://fangzhouxing.javaeye.com/blog/147539">单元测试</a>
          <br/>
          <span style="color:red;">
            <a href="http://fangzhouxing.javaeye.com/blog/147054#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/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/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 09 Dec 2007 15:38:00 +0800</pubDate>
        <link>http://fangzhouxing.javaeye.com/blog/147054</link>
        <guid>http://fangzhouxing.javaeye.com/blog/147054</guid>
      </item>
      <item>
        <title>JBoss Seam (POJO without EJB) 后台 + ExtJS 前台完整例子（八）</title>
        <author>fangzhouxing</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://fangzhouxing.javaeye.com">fangzhouxing</a>&nbsp;
          链接：<a href="http://fangzhouxing.javaeye.com/blog/146966" style="color:red;">http://fangzhouxing.javaeye.com/blog/146966</a>&nbsp;
          发表时间: 2007年12月09日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h1>JBoss Seam (POJO without EJB) 后台 + ExtJS 前台完整例子（八）</h1>
<br />
<strong>1.引言</strong><br />
<br />
AJAX应用具有表现力丰富、更加互动和更加迅速的响应等特点，这些特点都是通过使用XMLHttpRequest对象来动态的载入数据而获得的，而不是重新载入新的页面。在应用这一抽象层次，需要有比直接操作XMLHttpRequest对象更加方便的前后台通讯机制。<br />
<br />
本文介绍Java后台和前后的几种常用的通讯机制和实现方法。<br />
<br />
<strong>2. JSON</strong><br />
<br />
<a href="http://json.org/json-zh.html">JSON</a>(JavaScript Object Notation) 是前后台数据交换的一种格式。由于它可以直接转换为JavaScript的内部数据结构，所以成为AJAX应用的<a href="http://dev2dev.bea.com.cn/techdoc/2007/03/java-soa-introduction-json.html">首选数据交换格式</a>。<br />
<br />
在ExtJS中，使用数据集作为数据源的器件，如网格、下拉列表等，都规定了能够接受的后台JSON数据格式。在《ext tutorial》的第2章&ldquo;<a href="http://203.93.254.59:8888/extdoc/html/ext-ch-02.html">2. 震撼吧！让你知道ext表格控件的厉害。</a>&rdquo; 中, 对作为网格数据源的JSON格式有非常清晰的描述。<br />
<br />
<strong>3. DWR/JBoss Seam Remoting</strong><br />
<br />
用Java作为后台的开发人员有福了！使用<a href="http://getahead.org/dwr ">DWR</a>(Direct Web Remoting) 或 <a href="http://www.ibm.com/developerworks/cn/java/j-seam3/">JBoss Seam Remoting</a>后，我们可以直接调用后台的方法，就像调用本地JS方法一样。还有比这样做更加简单的方法吗？！<br />
<br />
DWR和JBoss Seam Remoting是两种十分类似的技术，在 divo.js 中，提供了通用的方法屏蔽这两种技术的差别：<br />
<div class="code_title">js 代码</div>
<div class="dp-highlighter">
<div class="bar"> </div>
<ol class="dp-c" start="1">
    <li class="alt"><span><span class="comment">/**</span> </span></li>
    <li class=""><span><span class="comment">* 远程[异步]调用服务器端方法</span> </span></li>
    <li class="alt"><span><span class="comment">* @param {String} method 格式为:类名.方法名</span> </span></li>
    <li class=""><span><span class="comment">* @param {Function} callba