<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>Groovy on Grails </title>
    <description>Groovy：敏捷的Java；Grails：敏捷的Java Web开发</description>
    <link>http://grails.group.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>Groovy 闭包深入浅出</title>
        <author>romejiang</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://romejiang.javaeye.com">romejiang</a>&nbsp;
          链接：<a href="http://grails.group.javaeye.com/group/blog/214812" style="color:red;">http://grails.group.javaeye.com/group/blog/214812</a>&nbsp;
          发表时间: 2008年07月15日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><strong>闭包概念</strong></p>
<p>Groovy语言中闭包（closure）是一个非常重要的概念，而且深入的理解了闭包对充分用好Groovy有很大帮助。对闭包比较书面的一种解释&ldquo;闭包是可以用作函数参数和方法参数的代码块&rdquo;。其实Groovy的闭包更象是一个&ldquo;代码块&rdquo;或者方法指针，代码在某处被定义然后在其后的调用处执行。</p>
<p>现在支持闭包的语言有 Scheme、Common Lisp、Smalltalk、Groovy、JavaScript、Perl，Ruby 和 Python 。</p>
<p><strong>闭包基础<br /></strong>来看一个例子：</p>
<p>def square = {it * it} // 定义一个叫square的闭包。it是默认的 参数名称</p>
<p>assert 4 == square(2) // 使用闭包</p>
<p>assert [1,4,9] == [1,2,3].collect(square) // 使用闭包</p>
<p><br />闭包类似Java的内类，区别是闭包只有单一的方法可以调用，但可以有任意的参数，闭包用&ldquo;{}&rdquo;括起，&ldquo;-&gt;&rdquo;前面是参数，后面是处理语句，可以直接调用，也可以使用call调用。不管那种调用，最后groovy编译器都会把编译成对doCall方法的调用，这是groovy对闭包的一个隐藏方法。</p>
<p>def closure = { param -&gt; println("hello ${param}") }<br />closure.call("world!")<br />&nbsp;<br />def closure = { greeting, name -&gt; println(greeting + name) }<br />closure.call("hello ", "world!")</p>
<p>第一个例子演示了在字符串内使用参数的形式：${param}<br />第二个例子演示了多参数形式：用&ldquo;，&rdquo;分隔参数</p>
<p>如果你的参数少于2个，那么它可以直接忽略掉。如果只有一个参数，可以不写，而使用缺省的参数&ldquo;it&rdquo;，如下面的例子：</p>
<p>closure = { println "hello " + it }<br />closure.call("world!")</p>
<p>把闭包当作变量返回的例子：<br />def localMethod() {<br />&nbsp; def localVariable = new java.util.Date()<br />&nbsp; return { println localVariable }<br />}<br />&nbsp;<br />def clos = localMethod()<br />&nbsp;<br />println "Executing the closure:"<br />clos()&nbsp; </p>
<p>&nbsp;</p>
<p><strong>Groovy闭包中几个隐含变量</strong></p>
<p>it：默认的参数名，调用是如果没有传参数，it为null<br />this : 跟Java一样，是定义闭包所在类的一个引用，不管有多少层闭包嵌套，this指向的都是最上层的类。<br />owner : 封闭闭包的对象(如果只有一层闭包就是this，如果有多层闭包嵌套就是含有此闭包的上层闭包)<br />delegate :缺省值是owner，但是可以改变，后面详说。<br />看例子：</p>
<p>class Class1 {<br />&nbsp; def closure = {<br />&nbsp;&nbsp;&nbsp; println " ============================== "<br />&nbsp;&nbsp;&nbsp; println "this = "+ this.class.name<br />&nbsp;&nbsp;&nbsp; println "owner = " + owner.class.name<br />&nbsp;&nbsp;&nbsp; println "delegate = " + delegate.class.name<br />&nbsp;&nbsp;&nbsp; def nestedClos = {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; println " ============================== "<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; println "this = "+ this.class.name<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; println "owner = " + owner.class.name<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; println "delegate = " + delegate.class.name<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def thirdClos = {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; println " ============================== "<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; println "this = "+ this.class.name<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; println "owner = " + owner.class.name<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; println "delegate = " + delegate.class.name<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thirdClos()&nbsp; <br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; nestedClos()<br />&nbsp; }<br />}<br />&nbsp;<br />def clos = new Class1().closure<br />//clos.delegate = this<br />clos()</p>
<p>执行结果：<br />&nbsp;============================== <br />this = Class1<br />owner = Class1<br />delegate = Class1<br />&nbsp;============================== <br />this = Class1<br />owner = Class1$_closure1<br />delegate = Class1$_closure1<br />&nbsp;============================== <br />this = Class1<br />owner = Class1$_closure1_closure2<br />delegate = Class1$_closure1_closure2</p>
<p><strong>闭包实现接口</strong></p>
<p>前面说了用闭包实现类，或继承其他类。现在看看怎么实现接口。</p>
<p><br />interface Test<br />{<br />&nbsp;def test()<br />}<br />&nbsp;<br />&nbsp;<br />def test = {<br />&nbsp;println'ok'<br />} as Test<br />&nbsp;&nbsp;&nbsp;&nbsp; <br />test.test()<br />如果接口只有一个方法需要实现，比如Comparator，Runnable等接口就可以直接实现方法后加上 as Runnable接口名就可以。</p>
<p>多方法接口，groovy用Map的方法实现。</p>
<p>interface MultiFuncTest<br />{<br />&nbsp;&nbsp;&nbsp; def test1()<br />&nbsp;&nbsp;&nbsp; def test2(str)<br />}<br />&nbsp;<br />&nbsp;<br />def impl = [test1:{println'test'},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; test2:{str -&gt; println str}] as MultiFuncTest</p>
<p><br />impl.test1()<br />impl.test2('ok')</p>
<p><br /><strong>delegate委托的用法</strong><br />delegate委托在是一种常用设计模式，但在java中实现相对比较繁琐，groovy直接在GroovyObject中已经实现了delegate模式，所以在groovy中应用delegate很方便。</p>
<p>class Dog{<br />&nbsp;&nbsp;&nbsp; def play = {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "wang wang!"<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; def childmind = {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; println&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delegate.play();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; }<br />}</p>
<p>class Cat {<br />&nbsp;&nbsp;&nbsp; def play = {"mi mi !"}<br />}</p>
<p>def dog = new Dog()<br />def cat = new Cat()</p>
<p>dog.childmind()</p>
<p>dog.childmind.delegate&nbsp; = cat;<br />dog.childmind()</p>
<p>上面的例子是狗爸爸让老猫帮忙照看他的狗儿子玩游戏。</p>
<p>闭包是Groovy一种核心技术，也是现在比较流行的动态语言的核心技术，所以全面稳定的掌握闭包是非常必要的。</p>
<p><br />参考：<br /><a href="http://blog.csdn.net/hivon/archive/2008/04/23/2318760.aspx">http://blog.csdn.net/hivon/archive/2008/04/23/2318760.aspx</a>&nbsp; Groovy探索之闭包 三<br /><a href="http://www.chinagroovy.org/groovywiki/doku.php/wiki:user_guide:closures">http://www.chinagroovy.org/groovywiki/doku.php/wiki:user_guide:closures</a> Groovy文档翻译，什么是闭包</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://grails.group.javaeye.com/group/blog/214812#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 15 Jul 2008 10:18:55 +0800</pubDate>
        <link>http://grails.group.javaeye.com/group/blog/214812</link>
        <guid>http://grails.group.javaeye.com/group/blog/214812</guid>
      </item>
      <item>
        <title>Grails中实现用户即时在线状态的记录与读取</title>
        <author>wenson</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wenson.javaeye.com">wenson</a>&nbsp;
          链接：<a href="http://grails.group.javaeye.com/group/blog/214678" style="color:red;">http://grails.group.javaeye.com/group/blog/214678</a>&nbsp;
          发表时间: 2008年07月14日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;之前有一需求：网站用户线上即时消费扣点，商户可以在线查看其商品的即时在线消费用户情况。目前网上查找到的资料有两种： <br />一是通过访问数据库，在数据库用户表比如Users表中添加一个字段 bit 当有人用这个用户登录的时候就把它变成1，但这方法会有以下问题：第一数据库更新问题，需要很大的性能而且如果大量用户这样做，后果不堪设想。第二:服务器无法判断设么时候用户推出登录； <br />二是通过JS来实现，但这种方法无法解决断网问题，还有就是如果一个用户在同一个计算机上登录两次那么第二次将不能登录，如果一个用户关闭浏览器服务器不知道，这个用户还想登录，后果就是登不上去了。 <br /><br />另外有一种个人觉得比较好的方案： <br />思想:就是用类似QQ的方法，如果一个用户再次登录，退出第一个登录的用户，保留第二个 <br />存储:利用用户池java.util.Map作为用户池容器,里面放着用户标示和sessionId,这个容器放到application对象中介可以; <br />原理:当用户登录时直接put进去就可以了，如果这个对象存在就会被更新 <br />其他:编写listener用HttpSessionAttributeListener地实现处理session属性的removed在removed的时候清楚这个用户在对象池中的状态 <br />检查:编写一个用户Filter来检查请求的sessionId和用户池是否匹配就可以了如果不匹配清楚这个session中的用户对象迫使下线 <br />针对项目使用的是Grails架构，把实现此功能的过程总结如下： <br />1、把消费记录记到application中，消费的controller为ConsumController.groovy,即时消费的action为:</p>
<pre name="code" class="java">def instantPay = {
        def personService = PersonService.get(params.id)
        def user = User.findByUserName(session.userName)
        if(!user){
            render(text:"請登入會員！",contentType:"text/html",encoding:"UTF-8")
        }
        int leftPoint = consumeRecordService.queryLeftPoint(user)
        if(leftPoint &lt; personService?.unitPrice){
            render "對不起，您的點數不夠，請充值！"
        }
        
        String consumeId = session.getAttribute("consumeId")
        Long consumeRecordId = consumeId?.toLong()
        //把該用戶添加到產品服務即時計費列表，列表保存在application当中
        def pscontext = request.session.servletContext

        Map serviceMap = pscontext.getAttribute("serviceMap")
        if(!serviceMap){
            serviceMap = new HashMap()
        }
        ConsumeRecord cvalue = serviceMap.get(consumeRecordId)

        if(!cvalue || cvalue?.member != user){
            serviceMap = presenceService.putPresence(consumeRecordId,serviceMap)
            pscontext.setAttribute ("serviceMap",serviceMap)
            
        }


        Long cid = new Long(0)

        if(consumeId != null &amp;&amp; !consumeId.equals("")){
           cid = consumeId.toLong()
        }
        Long id = consumeRecordService.getFirstConsume(cid, personService.id, user.id, 1, personService.unitPrice)

        session.setAttribute ("consumeId", id)
        
        leftPoint = consumeRecordService.queryLeftPoint(user)
        ConsumeRecord consumeRecord = ConsumeRecord.get(id)
        Date startTime = consumeRecord.startTime
        Date endTime = consumeRecord.endTime
        Long leftsec = ((endTime.getTime() - startTime.getTime())/1000)/60
        response.characterEncoding = "utf-8"
        render(text:"您已在線使用該服務時間為：${leftsec}分鐘，剩余點數為：${leftPoint}",contentType:"text/html")
       // render "您已使用的服務時間為：${leftsec}分鐘，剩余點數為：${leftPoint}"
    }</pre>
<p>此Controoler当中有用到presenceService来对保存在application中的即时在线消费用户状态的管理，presenceService内容如下：</p>
<pre name="code" class="java">/**
 * Created by IntelliJ IDEA.
 * User: Administrator
 * Date: 2008-6-12
 * Time: 16:53:54
 * To change this template use File | Settings | File Templates.
 */
class PresenceService {
    boolean transactional = true
    Map allPresencesMap = new HashMap()
//保存到application中
    def Map putPresence(Long consumeId, Map serviceMap){
        ConsumeRecord consumeRecord = new ConsumeRecord()
        if(consumeId){
            consumeRecord = ConsumeRecord.get(consumeId)
        }

        if(serviceMap){
            allPresencesMap = serviceMap
        }
        allPresencesMap.put(consumeId,consumeRecord)
        return allPresencesMap
    }

//从application中删除
    def void removePresence(Long consumeId, Map serviceMap){
        if(serviceMap){
           serviceMap.remove(consumeId)
        }
    }
//从application中删除所有的的在线用户
    def void removePresenceList(Long personServiceId){
        Map ctx = personServices?.personService
        if ( ctx ) {
            personServices.remove( personServiceId );
            ctx.clear();
        }
    }
//从application中取得所有的在线用户
    def List getPresenceList(User SP, Map serviceMap){
        List result = [];
        if(serviceMap){
            for(m in serviceMap){
                ConsumeRecord consumeRecord = m.value
                if(consumeRecord &amp;&amp; consumeRecord?.id ){
                    if(consumeRecord?.serviceProvider.userName == SP.userName){
                        result &lt;&lt; consumeRecord
                    }
                }

            }

        }
        return result;
    }
//取得指定的在线用户
    def Presence getPresence( String key, Long personServiceId ) {

        Map ctx = personServices?.personService

        if ( !ctx ) {
            ctx = new HashMap();
            personServices.put( personServiceId, ctx );
        }

        Presence result = ( Presence ) ctx.get( key );

        return result;
    }

}</pre>
<p>&nbsp;<br />2、要即时地把在线消费的用户记录到application中，这里用到了JOB进行定时作业。在Grails中集合了quartz这个plugin，使用grails create-job OnlineCheck，内容如下：</p>
<pre name="code" class="java">import org.codehaus.groovy.grails.web.context.ServletContextHolder

class OnlineCheckJob {
    def startDelay = 60000
    def timeout = 1000 * 91 // execute job once in 1.5 seconds
    def group = "OnlineStatus"
    PresenceService presenceService
    def execute() {
        println "Job:refresh online status......."
        def cxt = ServletContextHolder.getServletContext()
        //取得保存在application中的serviceMap
        Map serviceMap = cxt.getAttribute("serviceMap")

        Date now = new Date();
        //如果serviceMap在application中存在，则对其进行遍历，取得即时在线消费的用户
        println("presenceService :${presenceService}")
        if(serviceMap){
            for(m in serviceMap){
                // Map comsumeMap = new HashMap();
                ConsumeRecord consumeRecord = m.value
                if(consumeRecord != null &amp;&amp; consumeRecord.id != null){
                    Date endTime = consumeRecord.endTime
                   //如果consumeRecord的最后消费时间大于当前时间65秒，则把当前在线消费的用户踢下线
             if(((now?.getTime() - endTime?.getTime()) / 1000 ) &gt; 65){
                        presenceService.removePresence (consumeRecord.id, serviceMap)
                        println("remove online status:consumeRecordId=${consumeRecord.id}")
                    }
                }

            }
        }
        
    }
}</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>3、记录到application中了之后，就可以从application中读取保存在里面的在线用户了，建立一个controller，读取在线状态的action为：</p>
<pre name="code" class="java">def onlinestatus= {
        User sp = User.findByUserName(session.userName)  //sp为商户
        def pscontext = request.session.servletContext
        Map serviceMap = pscontext.getAttribute("serviceMap")
        List result = presenceService.getPresenceList(sp,serviceMap)

        request.setAttribute ("resultList",result)
        //[resultList:result]

        [resultList:result]  
    }</pre>
<p>&nbsp;如果要即时获取此在线消费用户的列表，则要使用Ajax来定时执行此action了：</p>
<pre name="code" class="java">&lt;g:javascript&gt;

function timerUpdater() {
              var myAjax = new Ajax.PeriodicalUpdater(
              {success:'onlinelist'},// 成功或失敗更新的页面div元素
                      '/user/onlinestatus', // 请求的URL
              {
                  asynchronous:true,
                  method: 'post', // HTTP请求的方式为GET
                  evalScripts: true, // 是否执行请求页面中的脚本
                  frequency: 60, // 更新的频率
                  decay: 2 // 衰减系数
              }
                      );
              return false;
          }
&lt;/g:javascript&gt;</pre>
<p>&nbsp;</p>
<p>&nbsp;保存所有之后，即可运行测试了。。。。。。。。</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://grails.group.javaeye.com/group/blog/214678#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 14 Jul 2008 19:41:35 +0800</pubDate>
        <link>http://grails.group.javaeye.com/group/blog/214678</link>
        <guid>http://grails.group.javaeye.com/group/blog/214678</guid>
      </item>
      <item>
        <title>grails JobExecutionException编译错误</title>
        <author>agile_boy</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://agile-boy.javaeye.com">agile_boy</a>&nbsp;
          链接：<a href="http://grails.group.javaeye.com/group/blog/212679" style="color:red;">http://grails.group.javaeye.com/group/blog/212679</a>&nbsp;
          发表时间: 2008年07月08日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          使用Grails插件的要注意了，jsecurity中自带了一个quartz.jar，因此如果同时使用quartz和jsecurity插件的话，就会出现：找不到符号JobExecutionException的编译错误，原因就是如上所说。<br />  <br />  解决办法很简单，将jsecurity的lib的quartz.jar去掉吧。
          <br/>
          <span style="color:red;">
            <a href="http://grails.group.javaeye.com/group/blog/212679#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 08 Jul 2008 11:46:50 +0800</pubDate>
        <link>http://grails.group.javaeye.com/group/blog/212679</link>
        <guid>http://grails.group.javaeye.com/group/blog/212679</guid>
      </item>
      <item>
        <title>给Grails添加验证码插件</title>
        <author>romejiang</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://romejiang.javaeye.com">romejiang</a>&nbsp;
          链接：<a href="http://grails.group.javaeye.com/group/blog/212622" style="color:red;">http://grails.group.javaeye.com/group/blog/212622</a>&nbsp;
          发表时间: 2008年07月08日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>在Grails安全验证插件分类中有几个和验证码相关的插件。<br />Simple Captcha Plugin&nbsp; ： 比较简单的实现了图片显示验证码<br />JCaptcha Plugin ：基于 JCaptcha 开源图片和音频验证码项目的Grails插件<br />ReCaptcha Plugin ：基于 ReCaptcha 开源图片和音频验证码项目的Grails插件</p>
<p>这次主要介绍如何使用 JCaptcha 插件，因为JCaptcha相对比较成熟和稳定，功能完善可调整的内容也比较丰富。</p>
<p><strong></strong></p>
<p><strong></strong></p>
<p><strong>安装</strong><br />在 <a href="http://plugins.grails.org/">http://plugins.grails.org</a> 网站下载 JCaptcha 插件。<br />然后进入你的项目目录， grails install-plugin %path%/grails-jcaptcha-0.2.zip </p>
<p>这里没有使用Grails的自动安装因为那样很慢，而且Grails自己下载也不支持断点，所以还是自己下载来的方便，特别是比较大的插件。</p>
<p>&nbsp;</p>
<p><strong></strong></p>
<p><strong>配置</strong></p>
<p>在grails-app/conf/Config.groovy 文件中 定义验证器（captchas），</p>
<p>定义例子如下：</p>
<p>&nbsp;</p>
<pre name="code" class="java">import java.awt.Font
import java.awt.Color
import com.octo.captcha.service.multitype.GenericManageableCaptchaService
import com.octo.captcha.engine.GenericCaptchaEngine
import com.octo.captcha.image.gimpy.GimpyFactory
import com.octo.captcha.component.word.wordgenerator.RandomWordGenerator
import com.octo.captcha.component.image.wordtoimage.ComposedWordToImage
import com.octo.captcha.component.image.fontgenerator.RandomFontGenerator
import com.octo.captcha.component.image.backgroundgenerator.GradientBackgroundGenerator
import com.octo.captcha.component.image.color.SingleColorGenerator
import com.octo.captcha.component.image.textpaster.NonLinearTextPaster
import com.octo.captcha.service.sound.DefaultManageableSoundCaptchaService


jcaptchas {
 imageCaptcha = new GenericManageableCaptchaService(
  new GenericCaptchaEngine(
   new GimpyFactory(
    new RandomWordGenerator(
     "abcdefghijklmnopqrstuvwxyz1234567890"
    ),
    new ComposedWordToImage(
     new RandomFontGenerator(
      20, // min font size
      30, // max font size
      [new Font("Arial", 0, 10)] as Font[]
     ),
     new GradientBackgroundGenerator(
      140, // width
      35, // height
      new SingleColorGenerator(new Color(0, 60, 0)),
      new SingleColorGenerator(new Color(20, 20, 20))
     ),
     new NonLinearTextPaster(
      6, // minimal length of text
      6, // maximal length of text
      new Color(0, 255, 0)
     )
    )
   )
  ),
  180, // minGuarantedStorageDelayInSeconds
  180000 // maxCaptchaStoreSize
 ) 
 soundCaptcha = new DefaultManageableSoundCaptchaService()
}
</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>上面的代码是定义了两个验证器（captcha），一个图形验证器 imageCaptcha ，一个音频验证器 soundCaptcha；<br />imageCaptcha使用了自定义的方式，配置了很多参数。默认的图像验证器是 DefaultManageableImageCaptchaService<br />soundCaptcha使用了默认的验证器。</p>
<p>&nbsp;</p>
<p>你可以配置更多的验证器以及规则，也可以就配置一个，比如这个音频的验证器一般不需要就可以删除掉。如果因为你的业务需要你要一个六字的验证和一个四字的验证，这样的情况就可以配置两个图像验证器。</p>
<p>ps：我在使用音频验证器时grails报错，因为音频使用到了一些音频处理的API，而我没有这些包，所以删除音频验证器以及涉及音频验证器的包即可。如果你确实需要音频验证器，那就你看错误信息，找到这些包然后放在项目的lib里。</p>
<p>ps：安装 JCaptcha 插件时会在plugins中安装插件的项目结构，其中也会安装conf/Config.groovy文件。如果运行Grails发生Config.groovy错误，删除插件中的配置文件即可plugins\jcaptcha-0.2\grails-app\conf\Config.groovy</p>
<p><strong></strong></p>
<p><strong>显示</strong></p>
<p>完成上面的配置之后，你得到一个验证器名称：imageCaptcha 。然后在需要的gsp页面中使用下面的tag。<br />&lt;jcaptcha:jpeg name="&lt;captchaname&gt;"&nbsp; /&gt; <br />&nbsp;<br />&lt;captchaname&gt;就是你的验证器名称：imageCaptcha </p>
<p>正常的情况下你就可以看到验证图片了。这个验证图片的颜色，字体，大小，内容都可以通过前面的自定义配置去修改和完善。</p>
<p><strong></strong></p>
<p><strong>验证</strong></p>
<p>在控制器中需要验证用户输入的验证码和验证图片中显示的是否一致。首先要在控制器中声明一个jcaptchaService对象，以便spring依赖注入 jcaptchaService 这个类。<br />然后在具体的验证Action中使用jcaptchaService.validateResponse("imageCaptcha", session.id, params.code)方法具体验证。<br />第一个参数是你的验证器名称。<br />第二个参数是比较固定就是 session.id<br />第三个参数是 页面中填写验证码输入框的内容，根据你的输入框的名字XXX，params.XXX</p>
<pre name="code" class="ruby">def jcaptchaService    
def save = {
 def user = new User(params)
        if (!jcaptchaService.validateResponse("captchaName", session.id, params.captchaResponse))
        {
          flash.message = "认证码错误！"
          return render(view:'index',model:[user:user])  
 }

 // other logic
}

</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><strong>高级玩法<br /></strong>前面在配置图像验证器时我们已经发现，我们可以通过配置改变验证图片的很多特性。现在深入看看我们都能改变什么。</p>
<p>new RandomWordGenerator("") 可以配置随机生成图片内容的字符范围</p>
<p>&nbsp;</p>
<pre name="code" class="java">new ComposedWordToImage(
 new RandomFontGenerator( // 生成图片文字的字体以及字号大小，可以是多种字体，会随机出现。
  20, // min font size
  30, // max font size
  [new Font("Arial", 0, 10)] as Font[]
 ),
 new GradientBackgroundGenerator(// 配置验证图片的大小和背景色以及过渡色
  140, // width
  35, // height
  new SingleColorGenerator(new Color(0, 60, 0)),
  new SingleColorGenerator(new Color(20, 20, 20))
 ),
 new NonLinearTextPaster(
  6, // minimal length of text
  6, // maximal length of text
  new Color(0, 255, 0)
 )
)</pre>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://grails.group.javaeye.com/group/blog/212622#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 08 Jul 2008 10:23:09 +0800</pubDate>
        <link>http://grails.group.javaeye.com/group/blog/212622</link>
        <guid>http://grails.group.javaeye.com/group/blog/212622</guid>
      </item>
      <item>
        <title>Grails 现有插件的介绍</title>
        <author>romejiang</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://romejiang.javaeye.com">romejiang</a>&nbsp;
          链接：<a href="http://grails.group.javaeye.com/group/blog/212616" style="color:red;">http://grails.group.javaeye.com/group/blog/212616</a>&nbsp;
          发表时间: 2008年07月08日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div style="background: white; margin: 0cm 0cm 6.8pt; line-height: 19.2pt;"><span style="font-size: 12pt;">本页面介绍了grails现今能用的插件连接。如果想自己开发插件请查看<a href="http://www.grails.org/The+Plug-in+Developers+Guide">The Plug-in Developers Guide</a>。</span></div>
<div style="background: white; margin: 6.8pt 0cm; line-height: 21.6pt;"><strong><span style="font-size: 21.5pt; color: #002445; letter-spacing: -0.1pt;">Testing</span></strong></div>
<div style="background: white; margin: 6.8pt 0cm; line-height: 21.6pt;"><strong><span style="font-size: 21.5pt; color: #002445; letter-spacing: -0.1pt;">测试类的插件</span></strong></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Functional+Testing">Functional Testing</a> with Canoo WebTest </span></li>
</ul>
<div style="background: white; margin: 0cm 0cm 0pt 36pt; line-height: 19.2pt;"><span style="font-size: 12pt;">功能测试的插件，利用开源框架</span><a href="http://webtest.canoo.com/">Canoo WebTest</a>.</div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Test+Code+Coverage+Plugin">Test Code Coverage Plugin</a> </span></li>
</ul>
<div style="background: white; margin: 0cm 0cm 0pt 17.95pt; text-indent: 18pt; line-height: 19.2pt;"><span style="font-size: 12pt;">代码覆盖率的测试插件，</span>grails install-plugin code-coverage</div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Selenium+plugin">Selenium plugin</a> (run functional tests in the browser) </span></li>
</ul>
<div style="background: white; margin: 0cm 0cm 0pt 36pt; line-height: 19.2pt;"><span style="font-size: 12pt;">Selenium </span><span style="font-size: 12pt;">的web插件（可在浏览器端进行功能测试）</span></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/jsUnit+plugin">jsUnit plugin</a> (test javascript) </span></li>
</ul>
<div style="background: white; margin: 0cm 0cm 0pt 36pt; line-height: 19.2pt;"><span style="font-size: 12pt;">javascript</span><span style="font-size: 12pt;">的测试插件，可以测试一个javascript的方法，形式类似于java的测试框架junit</span></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/DBUnit+Plugin">DBUnit Plugin</a> &nbsp;&nbsp;&nbsp;</span><span style="font-size: 12pt;">好像很复杂 http://www.grails.org/DBUnit+Plugin</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Debug+Plugin">Debug Plugin</a> Provides useful debug output of request params, model and useful functionality </span></li>
</ul>
<div style="background: white; margin: 0cm 0cm 0pt 36pt; line-height: 19.2pt;"><span style="font-size: 12pt;">方便在开发的时候随处打印我们需要检测的变量，只能运行在开发模式下。在GSP中用类似于</span>&lt;debug:info category="params"/&gt;的语句即可看到params中的所有参数结果。安装：&ldquo;grails install-plugin debug&rdquo;。详细见http://www.grails.org/Debug+Plugin</div>
<div style="background: white; margin: 6.8pt 0cm; line-height: 21.6pt;"><strong><span style="font-size: 21.5pt; color: #002445; letter-spacing: -0.1pt;">Rich Client/Ajax Plugins</span></strong></div>
<div style="background: white; margin: 6.8pt 0cm; line-height: 21.6pt;"><strong><span style="font-size: 21.5pt; color: #002445; letter-spacing: -0.1pt;">富客户端</span></strong><strong><span style="font-size: 21.5pt; color: #002445; letter-spacing: -0.1pt;">/Ajax</span></strong></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/DWR+Plugin">DWR Plugin</a> </span></li>
</ul>
<div style="background: white; margin: 0cm 0cm 0pt 18pt; line-height: 19.2pt;"><span style="font-size: 12pt;">Ajax</span><span style="font-size: 12pt;">的一个插件，apache的一个开源项目，安装&ldquo;</span>grails install-plugin dwr<span style="font-size: 12pt;">&rdquo;</span></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Dynamic+Javascript+Plugin">Dynamic Javascript Plugin</a> </span></li>
</ul>
<div style="background: white; margin: 0cm 0cm 0pt 18pt; line-height: 19.2pt;"><span style="font-size: 12pt;">动态javascript插件，利用他可以生成一个ajax响应的</span>controllers层。</div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Echo2+Plugin">Echo2 Plugin</a> </span><span style="font-size: 9.5pt; color: #111111;">echo</span><span style="font-size: 9.5pt; color: #111111;">可以让开发者象开发</span><span style="font-size: 9.5pt; color: #111111;">awt/swing</span><span style="font-size: 9.5pt; color: #111111;">应用程序一样</span><span style="font-size: 9.5pt; color: #111111;">,</span><span style="font-size: 9.5pt; color: #111111;">用面向对象的方式设计</span><span style="font-size: 9.5pt; color: #111111;">web</span><span style="font-size: 9.5pt; color: #111111;">界面</span><span style="font-size: 9.5pt; color: #111111;">.</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/GWT+Plugin">GWT Plugin</a>&nbsp;&nbsp; </span><a href="http://code.google.com/webtoolkit/">Google Web Toolkit</a>（GWT）google的ajax framework。 </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/OpenLaszlo+Plugin">OpenLaszlo Plugin</a>&nbsp; OpenLaszlo是一个基于flash和js的富客户端框架，可以生成flash页面和js的页面。</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/RichUI+Plugin">RichUI Plugin</a> </span></li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/ZK+Plugin">ZK Plugin</a></span><span style="font-size: 12pt;">一个丰富用户界面的javascript框架</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Flex+Plugin">Flex Plugin</a> </span><span style="font-size: 12pt;">这个就是Flex的差价，Flex是flash的语言</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/ULC+Plugin">ULC Plugin</a> </span></li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/ModalBox+Plugin">ModalBox Plugin</a> javascript</span><span style="font-size: 12pt;">框架，一种model窗口</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/YUI+Plugin">Yahoo! UI Library (YUI) Plugin</a> </span></li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Ext+Plugin">Ext JavaScript Library Plugin</a> (discontinued) EXT</span><span style="font-size: 12pt;">的lib插件，没有什么配置，仅仅是下载了lib文件</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/SyntaxHighlighter+Plugin">Syntax Highlighter Plugin</a> </span><span style="font-size: 12pt;">语法的高亮插件，貌似不错，还没有看到。网页好慢啊</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/J2D+Plugin">J2D Plugin (Java2D+Graphics)</a> </span></li>
</ul>
<div style="background: white; margin: 6.8pt 0cm; line-height: 21.6pt;"><strong><span style="font-size: 21.5pt; color: #002445; letter-spacing: -0.1pt;">Chart Plugins</span></strong></div>
<div style="background: white; margin: 6.8pt 0cm; line-height: 21.6pt;"><strong><span style="font-size: 21.5pt; color: #002445; letter-spacing: -0.1pt;">图表的插件</span></strong></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Google+Chart+Plugin">Google Chart Plugin</a> google</span><span style="font-size: 12pt;">的制表制图插件</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/JFreeChart+Eastwood+Plugin">JFreeChart Eastwood Plugin</a>&nbsp;效仿GoogleChartAPI实现的基于JFreeChart的servlet工具插件</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Open+Flash+Chart+Plugin">Open Flash Chart Plugin</a> falsh</span><span style="font-size: 12pt;">的图表插件</span> </li>
</ul>
<div style="background: white; margin: 6.8pt 0cm; line-height: 21.6pt;"><strong><span style="font-size: 21.5pt; color: #002445; letter-spacing: -0.1pt;">Web Services Plugins<br />web服务</span></strong></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/XFire+plugin">XFire plugin</a> XFire是一个非常有名的Web Services框架</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Remoting+Plugin">Remoting Plugin</a> </span><span style="font-size: 12pt;">字面已经很明显了，让grails方便的使用Remoting</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/XML+RPC+Plugin">XML-RPC Plugin</a> &nbsp;</span><span style="font-size: 12pt;">让grails当但一个xml rpc的服务</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Apache+Axis2+Plugin">Apache Axis2 Plugin</a> Apache 的Web Service实现框架Axis2插件</span> </li>
</ul>
<div style="background: white; margin: 6.8pt 0cm; line-height: 21.6pt;"><strong><span style="font-size: 21.5pt; color: #002445; letter-spacing: -0.1pt;">Performance / Utility Plugins性能测试和工具</span></strong></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Static+Resources+Plugin">Static Resources Plugin</a> </span></li>
</ul>
<div style="background: white; margin: 0cm 0cm 0pt 18pt; line-height: 19.2pt;"><span style="font-size: 12pt;">&nbsp;</span><span style="font-size: 12pt;">通常情况下你存放图片或者上传的文件会将它放在你的程序之外的空间上，在服务器上你会用apache来定义，但是在你开发的时候你也会需要能访问他，这个时候你应该可以考虑用这个插件了。</span></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/p6spy+plugin">p6spy plugin</a> (database statement logging) </span><span style="font-size: 12pt;">可以监控你的jdbc连接，并且会生成logs让你方便的再次拿出来放在你使用的数据库客户端工具上，来测试他运行的结果。</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.syrics.de/pages/page/show/Cacheable%20Plugin">Cacheable Plugin</a> (application level caching) 应用程序级别的缓存插件（如果好用作用大大的）</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Amazon+S3+Plugin">Amazon S3 Plugin</a> &nbsp;Amazon S3</span><span style="font-size: 12pt;">服务器的插件，可惜买不起亚马逊的S3...</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/WebXML+Plugin">WebXML Plugin</a> Allows adding configurable features to the web.xml file without having to write a plugin. </span></li>
</ul>
<div style="background: white; margin: 0cm 0cm 0pt 17.95pt; text-indent: 18pt; line-height: 19.2pt;"><span style="font-size: 12pt;">大致的意思应该是说，通常情况下web.xml文件是以一个模板的形式来自动为你的grails 程序添加进去的，这也许只能方便一般的情况，如果我们要改动他，就很麻烦了，这个插件可以让他回归到我们开发java时候的那种情况。</span></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/jawr+plugin">Jawr plugin</a>&amp;nbsp;Javascript/CSS bundling and compression tool for grails web apps. All the features from the <a href="https://jawr.dev.java.net/">Jawr library</a> ported to Grails. </span></li>
</ul>
<div style="background: white; margin: 0cm 0cm 0pt 36pt; line-height: 19.2pt;"><span style="font-size: 12pt;">意思是，我们可以运用通配符来定义我们要引用的js或者css，然后我们在页面上引用的时候就方便只是引用我们定义的那个变量即可。当然这样的做法必须先前把所有的js和css的名字都定义很好。</span></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Profiler+Plugin">Profiler Plugin</a> for monitoring the performance of your Grails application. </span><span style="font-size: 12pt;">应该是一个监控性能的插件</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Compress+Plugin">Compress Plugin</a> - Compress Grails output &nbsp;</span><span style="font-size: 12pt;">压缩输出，至于怎么样用，文档太过简单。</span> </li>
</ul>
<div style="background: white; margin: 6.8pt 0cm; line-height: 21.6pt;"><strong><span style="font-size: 21.5pt; color: #002445; letter-spacing: -0.1pt;">Scheduling Plugins日程插件</span></strong></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Quartz+plugin">Quartz plugin</a> </span><span style="font-size: 12pt;">定时器，这个项目中已经再用了。</span> </li>
</ul>
<div style="background: white; margin: 6.8pt 0cm; line-height: 21.6pt;"><strong><span style="font-size: 21.5pt; color: #002445; letter-spacing: -0.1pt;">Security Plugins安全插件</span></strong></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/AcegiSecurity+Plugin">AcegiSecurity Plugin</a> </span><span style="font-size: 12pt;">整合Spring的Acegi 安全认证插件</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/JSecurity+Plugin">JSecurity Plugin</a> </span><span style="font-size: 12pt;">一个通用的安全认证框架</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Authentication+Plugin">Authentication Plugin</a> </span><span style="font-size: 12pt;">安全认证插件</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Simple+Captcha+Plugin">Simple Captcha Plugin</a> </span><span style="font-size: 12pt;">简单的说就是提交表单时候的认证图片。</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/JCaptcha+Plugin">JCaptcha Plugin</a> </span><span style="font-size: 12pt;">依然是一个表单提交的认证字</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/CAS+Client+Plugin">CAS Client Plugin</a></span><span style="font-size: 10pt;">为</span><span style="font-size: 10pt;">Web</span><span style="font-size: 10pt;">应用系统提供了单点登录服务</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/ClamAV+Plugin">ClamAV Plugin</a> </span><span style="font-size: 12pt;">一个防病毒的，环境是unix下。</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;">Atlassian <a href="http://www.grails.org/Crowd+Plugin">Crowd Plugin</a> </span><span style="font-size: 12pt;">？？？？？？？</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/OpenID+Plugin">OpenID Plugin</a> OpenID </span><span style="font-size: 12pt;">也就是说我们不需要在我们的应用中加入注册等这样的流程，这个插件会生成一个ID并且记录他分配给我们的用户。</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/OAuth+Plugin">OAuth Plugin</a> </span><span style="font-size: 10pt; color: #000000;">OAuth</span><span style="font-size: 10pt; color: #000000;">协议致力于使网站和应用程序（统称为消费方）能够在无须用户透露其认证证书的情况下，通过</span><span style="font-size: 10pt; color: #000000;">API</span><span style="font-size: 10pt; color: #000000;">访问某个</span><span style="font-size: 10pt; color: #000000;">web</span><span style="font-size: 10pt; color: #000000;">服务（统称为服务提供方）的受保护资源。更一般地说，</span><span style="font-size: 10pt; color: #000000;">OAuth</span><span style="font-size: 10pt; color: #000000;">为</span><span style="font-size: 10pt; color: #000000;">API</span><span style="font-size: 10pt; color: #000000;">认证提供了一个可自由实现且通用的方法</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/ReCaptcha+Plugin">ReCaptcha Plugin</a> </span><span style="font-size: 12pt;">这个嘛，一般来说就不要用了。貌似是一种服务，但是还需要在ReCaptcha的官方站上申请一个什么账号。麻烦</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/License+Plugin">License Management Plugin</a> </span><span style="font-size: 12pt;">安装 生成license的插件</span> </li>
</ul>
<div style="background: white; margin: 6.8pt 0cm; line-height: 21.6pt;"><strong><span style="font-size: 21.5pt; color: #002445; letter-spacing: -0.1pt;">Web Design Plugins网页设计插件</span></strong></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/sIFR+Plugin">sIFR Plugin</a> </span><span style="font-size: 14pt;">sIFR</span><span style="font-size: 14pt;">表示</span><span style="font-size: 14pt;">scalable Inman Flash Replacement</span><span style="font-size: 14pt;">，是一种在</span><span style="font-size: 14pt;">web</span><span style="font-size: 14pt;">上准确发布自定义排版的技术。这种技术的实现方法是，当页面下载时，在一个指定的元素中用</span><span style="font-size: 14pt;">Flash</span><span style="font-size: 14pt;">渲染的文字来代替一些文本。此插件就是干这个用的</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Skinnable+Plugin">Skinnable Plugin</a> </span><span style="font-size: 12pt;">这个比较有意思，应该是一个动态换肤（css）的插件，有空研究一下。</span> </li>
</ul>
<div style="background: white; margin: 6.8pt 0cm; line-height: 21.6pt;"><strong><span style="font-size: 21.5pt; color: #002445; letter-spacing: -0.1pt;">Search搜索插件</span></strong></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Searchable+Plugin">Searchable Plugin</a> - rich search functionality with minimum effort. Built on <a href="http://www.opensymphony.com/compass/">Compass</a> and <a href="http://lucene.apache.org/">Lucene</a> </span><span style="font-size: 12pt;">搜索的插件，应用的是lucene和compass不用说肯定要看看了。</span> </li>
</ul>
<div style="background: white; margin: 6.8pt 0cm; line-height: 21.6pt;"><strong><span style="font-size: 21.5pt; color: #002445; letter-spacing: -0.1pt;">Scaffolding / Templating / Binding plugins</span></strong></div>
<div style="background: white; margin: 6.8pt 0cm; line-height: 21.6pt;"><strong><span style="font-size: 21.5pt; color: #002445; letter-spacing: -0.1pt;">脚手架/模板/绑定</span></strong></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/DjangoTemplates+Plugin">DjangoTemplates Plugin</a> </span><span style="font-size: 12pt;">模板，呵呵这个就不用说了，不过有什么好处需要试验以后再详说。</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/GroovyBinder+Plugin">GroovyBinder Plugin</a> </span><span style="font-size: 12pt;">我晕死了，好像是一个很好的东西，</span> <span>dynamic write-only</span>。 </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/ScaffoldTags+Plugin">ScaffoldTags Plugin</a> </span><span style="font-size: 12pt;">不用说了，（就是Grails自带的脚手架吗？？）。</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/I18n+Templates+Plugin">I18n Templates Plugin</a> </span><span style="font-size: 12pt;">这个也不用说了，项目中已经再用了</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Extended+Data+Binding+Plugin">Extended Data Binding Plugin</a> </span></li>
</ul>
<div style="background: white; margin: 0cm 0cm 6.8pt; line-height: 19.2pt;"><span style="font-size: 12pt;">The extended data binding plugin allows configuring the DataBinder which controllers will use to parse the user input and populate objects, as well as wrapping objects to format data as strings in order to display data.(</span><span style="font-size: 12pt;">我不甚明白)</span></div>
<div style="background: white; margin: 6.8pt 0cm; line-height: 21.6pt;"><strong><span style="font-size: 21.5pt; color: #002445; letter-spacing: -0.1pt;">Persistence Plugins持久插件</span></strong></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Explicit+Insert+Plugin">Explicit Insert Plugin</a> adds an insert method to all domain classes to resolve save() issues with legacy tables with assigned keys and no version or timestamp. </span><span style="font-size: 12pt;">此插件是用在grails 1.0.2之前版本的。所以基本我们是不会用到的。</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Acts+As+Taggable+Plugin">Acts As Taggable Plugin</a> add the acts_as_taggable ability to domain class </span><span style="font-size: 12pt;">从Rails来的一个tag（标签）的插件，可以很方便的使用插件。</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Systemi+Grails+Domain+Plugin">Systemi Grails Domain Plugin</a> generates Grails domain classes from a legacy IBM System i (a.k.a. AS/400, a.k.a. iSeries) table </span></li>
</ul>
<div style="background: white; margin: 0cm 0cm 0pt 18pt; line-height: 19.2pt;"><span style="font-size: 12pt;">从一个IBM I table中生成Grails domain<span>&nbsp;&nbsp; </span>不知道能怎么样。</span></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Grails+Audit+Logging+Plugin">Grails Audit Logging Plugin</a> track who changed what via Hibernate events, can be optionally configured to log users from multiple security plugins, adds onChange event handler to marked domain classes and exposes old and new values. </span></li>
</ul>
<div style="background: white; margin: 6.8pt 0cm; line-height: 21.6pt;"><strong><span style="font-size: 21.5pt; color: #002445; letter-spacing: -0.1pt;">Functionality plugins</span></strong></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Radeox+plugin">Radeox plugin</a> for the Radeox wiki engine 一个wiki系统Radeox，以后可以用Grails方便的写出wiki程序啦~~</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Mondrian+plugin">Mondrian plugin</a> to add Mondrian and JPivot OLAP </span></li>
</ul>
<div style="background: white; margin: 0cm 0cm 0pt 18pt; line-height: 19.2pt;"><span style="font-size: 12pt;">OLAP</span><span style="font-size: 12pt;">（</span><span style="font-weight: normal; font-size: 12pt;">联机分析处理）的插件，具体做什么，偶不晓得了。</span></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/FCK+editor+plugin">FCK editor plugin</a> - WYSIWYG text editor with buillt in image and flash upload capabilities. </span></li>
</ul>
<div style="background: white; margin: 0cm 0cm 0pt 18pt; line-height: 19.2pt;"><span style="font-size: 12pt;">这个嘛就是一个富媒体编辑器的插件。</span></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/JMS+Plugin">JMS Plugin</a> to add Message Driven Bean functionality</span> </li>
</ul>
<div style="background: white; margin: 0cm 0cm 0pt 18pt; line-height: 19.2pt;"><span style="font-size: 12pt;">&nbsp;</span><span style="font-size: 12pt;">加入消息驱动器的插件，好东西</span></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Feeds+Plugin">Feeds Plugin</a> to generate RSS/Atom feeds easily </span></li>
</ul>
<div style="background: white; margin: 0cm 0cm 0pt 18pt; line-height: 19.2pt;"><span style="font-size: 12pt;">生成rss和Atom的插件，这个，，，Grails好像本来就做的挺好的吧！！</span></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/ImageTools+plugin">ImageTools plugin</a> provides some JAI helper classes for image handling </span></li>
</ul>
<div style="background: white; margin: 0cm 0cm 0pt 18pt; line-height: 19.2pt;"><span style="font-size: 12pt;">首先说JAI（</span><span style="font-size: 9.5pt; color: #444444;">Java Advanced Imaging</span><span style="font-size: 12pt;">）java&nbsp;image处理的扩展类。这个插件也就是加入了一些这样的类库进来（好东西!!!）。</span></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Currencies+plugin">Currencies plugin</a> provide Money and Exchange Rate handling classes. </span></li>
</ul>
<div style="background: white; margin: 0cm 0cm 0pt 18pt; line-height: 19.2pt;"><span style="font-size: 12pt;">提供一个货币兑换的一个操作类</span></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Encryption+plugin">Encryption plugin</a>, for Blowfish and PGP encryption, as well as handling salted passwords. 使用Blowfish 和PGP 加密的插件，应该是对字符串加密</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/PostCode+Plugin">PostCode Plugin</a> provides UK postcode lookup to lat/lon and distance between postcode functionality </span><span style="font-size: 12pt;">邮政编码，还是英国的。暂时没用</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Ref+Code+Plugin">Ref Code Plugin</a> provides funtionality for storing and accessing simple reference data </span></li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Mail+Plugin">Mail Plugin</a> - provides e-mail sending functionality to a Grails application </span><span style="font-size: 12pt;">为你的程序提供邮件发送功能。</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/PayPal+Plugin">PayPal Plugin</a> - Provides integration with PayPal transactions and the PayPal IPN ，PayPal 的插件，方便加入PayPal 支付代码</span> </li>
</ul>
<div style="background: white; margin: 6.8pt 0cm; line-height: 21.6pt;"><strong><span style="font-size: 21.5pt; color: #002445; letter-spacing: -0.1pt;">Other Frameworks其他框架</span></strong></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Wicket+Plugin">Wicket Plugin</a> Wicket也是一种MVC，像JSF一样用前端很多标签堆砌页面</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Struts+1+Plugin">Struts 1 Plugin</a>&nbsp; Struts1？？？祖宗辈的MVC框架。</span> </li>
</ul>
<div style="background: white; margin: 6.8pt 0cm; line-height: 21.6pt;"><strong><span style="font-size: 21.5pt; color: #002445; letter-spacing: -0.1pt;">Database Change Tracking数据库变更日志</span></strong></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.liquibase.org/manual/grails">LiquiBase Plugin</a> </span><span style="font-size: 12pt;">可以记录你的数据库的变更，生成的文件为XML</span> </li>
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://code.google.com/p/dbmigrate/wiki/Grails">dbmigrate Plugin</a> </span></li>
</ul>
<div style="background: white; margin: 6.8pt 0cm; line-height: 21.6pt;"><strong><span style="font-size: 21.5pt; color: #002445; letter-spacing: -0.1pt;">LDAP</span></strong></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/LDAP+Plugin">LDAP Plugin</a> - Add LDAP connectivity through <a href="http://ldaley.com/gldapo">Gldapo</a> 为Grails加入 目录访问框架<a href="http://ldaley.com/gldapo">Gldapo</a> 的功能</span> </li>
</ul>
<div style="background: white; margin: 6.8pt 0cm; line-height: 21.6pt;"><strong><span style="font-size: 21.5pt; color: #002445; letter-spacing: -0.1pt;">Report报表插件</span></strong></div>
<ul type="disc">
<li style="background: white; line-height: 19.2pt; text-align: left;"><span style="font-size: 12pt;"><a href="http://www.grails.org/Jasper+Plugin">Jasper Plugin</a> - Add Jasper reports in your web application easily. </span>不用说他是用来生成报表的 </li>
</ul>
          <br/>
          <span style="color:red;">
            <a href="http://grails.group.javaeye.com/group/blog/212616#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 08 Jul 2008 10:19:18 +0800</pubDate>
        <link>http://grails.group.javaeye.com/group/blog/212616</link>
        <guid>http://grails.group.javaeye.com/group/blog/212616</guid>
      </item>
      <item>
        <title>groovy MetaClass 剖析 1</title>
        <author>jimichan</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://jimichan.javaeye.com">jimichan</a>&nbsp;
          链接：<a href="http://grails.group.javaeye.com/group/blog/212082" style="color:red;">http://grails.group.javaeye.com/group/blog/212082</a>&nbsp;
          发表时间: 2008年07月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><!--          [if gte mso 9]><xml>
 <w:WordDocument>
  <w:View>Normal</w:View>
  <w:Zoom>0</w:Zoom>
  <w:TrackMoves/>
  <w:TrackFormatting/>
  <w:PunctuationKerning/>
  <w:DrawingGridVerticalSpacing>7.8 磅</w:DrawingGridVerticalSpacing>
  <w:DisplayHorizontalDrawingGridEvery>0</w:DisplayHorizontalDrawingGridEvery>
  <w:DisplayVerticalDrawingGridEvery>2</w:DisplayVerticalDrawingGridEvery>
  <w:ValidateAgainstSchemas/>
  <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>
  <w:IgnoreMixedContent>false</w:IgnoreMixedContent>
  <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>
  <w:DoNotPromoteQF/>
  <w:LidThemeOther>EN-US</w:LidThemeOther>
  <w:LidThemeAsian>ZH-CN</w:LidThemeAsian>
  <w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript>
  <w:Compatibility>
   <w:SpaceForUL/>
   <w:BalanceSingleByteDoubleByteWidth/>
   <w:DoNotLeaveBackslashAlone/>
   <w:ULTrailSpace/>
   <w:DoNotExpandShiftReturn/>
   <w:AdjustLineHeightInTable/>
   <w:BreakWrappedTables/>
   <w:SnapToGridInCell/>
   <w:WrapTextWithPunct/>
   <w:UseAsianBreakRules/>
   <w:DontGrowAutofit/>
   <w:SplitPgBreakAndParaMark/>
   <w:DontVertAlignCellWithSp/>
   <w:DontBreakConstrainedForcedTables/>
   <w:DontVertAlignInTxbx/>
   <w:Word11KerningPairs/>
   <w:CachedColBalance/>
   <w:UseFELayout/>
  </w:Compatibility>
  <w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel>
  <m:mathPr>
   <m:mathFont m:val="Cambria Math"/>
   <m:brkBin m:val="before"/>
   <m:brkBinSub m:val="&#45;-"/>
   <m:smallFrac m:val="off"/>
   <m:dispDef/>
   <m:lMargin m:val="0"/>
   <m:rMargin m:val="0"/>
   <m:defJc m:val="centerGroup"/>
   <m:wrapIndent m:val="1440"/>
   <m:intLim m:val="subSup"/>
   <m:naryLim m:val="undOvr"/>
  </m:mathPr></w:WordDocument>
</xml><![endif]--><!--          [if gte mso 9]><xml>
 <w:LatentStyles DefLockedState="false" DefUnhideWhenUsed="true"
  DefSemiHidden="true" DefQFormat="false" DefPriority="99"
  LatentStyleCount="267">
  <w:LsdException Locked="false" Priority="0" SemiHidden="false"
   UnhideWhenUsed="false" QFormat="true" Name="Normal"/>
  <w:LsdException Locked="false" Priority="9" SemiHidden="false"
   UnhideWhenUsed="false" QFormat="true" Name="heading 1"/>
  <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 2"/>
  <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 3"/>
  <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 4"/>
  <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 5"/>
  <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 6"/>
  <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 7"/>
  <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 8"/>
  <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 9"/>
  <w:LsdException Locked="false" Priority="39" Name="toc 1"/>
  <w:LsdException Locked="false" Priority="39" Name="toc 2"/>
  <w:LsdException Locked="false" Priority="39" Name="toc 3"/>
  <w:LsdException Locked="false" Priority="39" Name="toc 4"/>
  <w:LsdException Locked="false" Priority="39" Name="toc 5"/>
  <w:LsdException Locked="false" Priority="39" Name="toc 6"/>
  <w:LsdException Locked="false" Priority="39" Name="toc 7"/>
  <w:LsdException Locked="false" Priority="39" Name="toc 8"/>
  <w:LsdException Locked="false" Priority="39" Name="toc 9"/>
  <w:LsdException Locked="false" Priority="35" QFormat="true" Name="caption"/>
  <w:LsdException Locked="false" Priority="10" SemiHidden="false"
   UnhideWhenUsed="false" QFormat="true" Name="Title"/>
  <w:LsdException Locked="false" Priority="1" Name="Default Paragraph Font"/>
  <w:LsdException Locked="false" Priority="11" SemiHidden="false"
   UnhideWhenUsed="false" QFormat="true" Name="Subtitle"/>
  <w:LsdException Locked="false" Priority="22" SemiHidden="false"
   UnhideWhenUsed="false" QFormat="true" Name="Strong"/>
  <w:LsdException Locked="false" Priority="20" SemiHidden="false"
   UnhideWhenUsed="false" QFormat="true" Name="Emphasis"/>
  <w:LsdException Locked="false" Priority="59" SemiHidden="false"
   UnhideWhenUsed="false" Name="Table Grid"/>
  <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Placeholder Text"/>
  <w:LsdException Locked="false" Priority="1" SemiHidden="false"
   UnhideWhenUsed="false" QFormat="true" Name="No Spacing"/>
  <w:LsdException Locked="false" Priority="60" SemiHidden="false"
   UnhideWhenUsed="false" Name="Light Shading"/>
  <w:LsdException Locked="false" Priority="61" SemiHidden="false"
   UnhideWhenUsed="false" Name="Light List"/>
  <w:LsdException Locked="false" Priority="62" SemiHidden="false"
   UnhideWhenUsed="false" Name="Light Grid"/>
  <w:LsdException Locked="false" Priority="63" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Shading 1"/>
  <w:LsdException Locked="false" Priority="64" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Shading 2"/>
  <w:LsdException Locked="false" Priority="65" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium List 1"/>
  <w:LsdException Locked="false" Priority="66" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium List 2"/>
  <w:LsdException Locked="false" Priority="67" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Grid 1"/>
  <w:LsdException Locked="false" Priority="68" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Grid 2"/>
  <w:LsdException Locked="false" Priority="69" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Grid 3"/>
  <w:LsdException Locked="false" Priority="70" SemiHidden="false"
   UnhideWhenUsed="false" Name="Dark List"/>
  <w:LsdException Locked="false" Priority="71" SemiHidden="false"
   UnhideWhenUsed="false" Name="Colorful Shading"/>
  <w:LsdException Locked="false" Priority="72" SemiHidden="false"
   UnhideWhenUsed="false" Name="Colorful List"/>
  <w:LsdException Locked="false" Priority="73" SemiHidden="false"
   UnhideWhenUsed="false" Name="Colorful Grid"/>
  <w:LsdException Locked="false" Priority="60" SemiHidden="false"
   UnhideWhenUsed="false" Name="Light Shading Accent 1"/>
  <w:LsdException Locked="false" Priority="61" SemiHidden="false"
   UnhideWhenUsed="false" Name="Light List Accent 1"/>
  <w:LsdException Locked="false" Priority="62" SemiHidden="false"
   UnhideWhenUsed="false" Name="Light Grid Accent 1"/>
  <w:LsdException Locked="false" Priority="63" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Shading 1 Accent 1"/>
  <w:LsdException Locked="false" Priority="64" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Shading 2 Accent 1"/>
  <w:LsdException Locked="false" Priority="65" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium List 1 Accent 1"/>
  <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Revision"/>
  <w:LsdException Locked="false" Priority="34" SemiHidden="false"
   UnhideWhenUsed="false" QFormat="true" Name="List Paragraph"/>
  <w:LsdException Locked="false" Priority="29" SemiHidden="false"
   UnhideWhenUsed="false" QFormat="true" Name="Quote"/>
  <w:LsdException Locked="false" Priority="30" SemiHidden="false"
   UnhideWhenUsed="false" QFormat="true" Name="Intense Quote"/>
  <w:LsdException Locked="false" Priority="66" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium List 2 Accent 1"/>
  <w:LsdException Locked="false" Priority="67" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Grid 1 Accent 1"/>
  <w:LsdException Locked="false" Priority="68" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Grid 2 Accent 1"/>
  <w:LsdException Locked="false" Priority="69" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Grid 3 Accent 1"/>
  <w:LsdException Locked="false" Priority="70" SemiHidden="false"
   UnhideWhenUsed="false" Name="Dark List Accent 1"/>
  <w:LsdException Locked="false" Priority="71" SemiHidden="false"
   UnhideWhenUsed="false" Name="Colorful Shading Accent 1"/>
  <w:LsdException Locked="false" Priority="72" SemiHidden="false"
   UnhideWhenUsed="false" Name="Colorful List Accent 1"/>
  <w:LsdException Locked="false" Priority="73" SemiHidden="false"
   UnhideWhenUsed="false" Name="Colorful Grid Accent 1"/>
  <w:LsdException Locked="false" Priority="60" SemiHidden="false"
   UnhideWhenUsed="false" Name="Light Shading Accent 2"/>
  <w:LsdException Locked="false" Priority="61" SemiHidden="false"
   UnhideWhenUsed="false" Name="Light List Accent 2"/>
  <w:LsdException Locked="false" Priority="62" SemiHidden="false"
   UnhideWhenUsed="false" Name="Light Grid Accent 2"/>
  <w:LsdException Locked="false" Priority="63" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Shading 1 Accent 2"/>
  <w:LsdException Locked="false" Priority="64" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Shading 2 Accent 2"/>
  <w:LsdException Locked="false" Priority="65" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium List 1 Accent 2"/>
  <w:LsdException Locked="false" Priority="66" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium List 2 Accent 2"/>
  <w:LsdException Locked="false" Priority="67" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Grid 1 Accent 2"/>
  <w:LsdException Locked="false" Priority="68" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Grid 2 Accent 2"/>
  <w:LsdException Locked="false" Priority="69" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Grid 3 Accent 2"/>
  <w:LsdException Locked="false" Priority="70" SemiHidden="false"
   UnhideWhenUsed="false" Name="Dark List Accent 2"/>
  <w:LsdException Locked="false" Priority="71" SemiHidden="false"
   UnhideWhenUsed="false" Name="Colorful Shading Accent 2"/>
  <w:LsdException Locked="false" Priority="72" SemiHidden="false"
   UnhideWhenUsed="false" Name="Colorful List Accent 2"/>
  <w:LsdException Locked="false" Priority="73" SemiHidden="false"
   UnhideWhenUsed="false" Name="Colorful Grid Accent 2"/>
  <w:LsdException Locked="false" Priority="60" SemiHidden="false"
   UnhideWhenUsed="false" Name="Light Shading Accent 3"/>
  <w:LsdException Locked="false" Priority="61" SemiHidden="false"
   UnhideWhenUsed="false" Name="Light List Accent 3"/>
  <w:LsdException Locked="false" Priority="62" SemiHidden="false"
   UnhideWhenUsed="false" Name="Light Grid Accent 3"/>
  <w:LsdException Locked="false" Priority="63" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Shading 1 Accent 3"/>
  <w:LsdException Locked="false" Priority="64" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Shading 2 Accent 3"/>
  <w:LsdException Locked="false" Priority="65" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium List 1 Accent 3"/>
  <w:LsdException Locked="false" Priority="66" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium List 2 Accent 3"/>
  <w:LsdException Locked="false" Priority="67" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Grid 1 Accent 3"/>
  <w:LsdException Locked="false" Priority="68" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Grid 2 Accent 3"/>
  <w:LsdException Locked="false" Priority="69" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Grid 3 Accent 3"/>
  <w:LsdException Locked="false" Priority="70" SemiHidden="false"
   UnhideWhenUsed="false" Name="Dark List Accent 3"/>
  <w:LsdException Locked="false" Priority="71" SemiHidden="false"
   UnhideWhenUsed="false" Name="Colorful Shading Accent 3"/>
  <w:LsdException Locked="false" Priority="72" SemiHidden="false"
   UnhideWhenUsed="false" Name="Colorful List Accent 3"/>
  <w:LsdException Locked="false" Priority="73" SemiHidden="false"
   UnhideWhenUsed="false" Name="Colorful Grid Accent 3"/>
  <w:LsdException Locked="false" Priority="60" SemiHidden="false"
   UnhideWhenUsed="false" Name="Light Shading Accent 4"/>
  <w:LsdException Locked="false" Priority="61" SemiHidden="false"
   UnhideWhenUsed="false" Name="Light List Accent 4"/>
  <w:LsdException Locked="false" Priority="62" SemiHidden="false"
   UnhideWhenUsed="false" Name="Light Grid Accent 4"/>
  <w:LsdException Locked="false" Priority="63" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Shading 1 Accent 4"/>
  <w:LsdException Locked="false" Priority="64" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Shading 2 Accent 4"/>
  <w:LsdException Locked="false" Priority="65" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium List 1 Accent 4"/>
  <w:LsdException Locked="false" Priority="66" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium List 2 Accent 4"/>
  <w:LsdException Locked="false" Priority="67" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Grid 1 Accent 4"/>
  <w:LsdException Locked="false" Priority="68" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Grid 2 Accent 4"/>
  <w:LsdException Locked="false" Priority="69" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Grid 3 Accent 4"/>
  <w:LsdException Locked="false" Priority="70" SemiHidden="false"
   UnhideWhenUsed="false" Name="Dark List Accent 4"/>
  <w:LsdException Locked="false" Priority="71" SemiHidden="false"
   UnhideWhenUsed="false" Name="Colorful Shading Accent 4"/>
  <w:LsdException Locked="false" Priority="72" SemiHidden="false"
   UnhideWhenUsed="false" Name="Colorful List Accent 4"/>
  <w:LsdException Locked="false" Priority="73" SemiHidden="false"
   UnhideWhenUsed="false" Name="Colorful Grid Accent 4"/>
  <w:LsdException Locked="false" Priority="60" SemiHidden="false"
   UnhideWhenUsed="false" Name="Light Shading Accent 5"/>
  <w:LsdException Locked="false" Priority="61" SemiHidden="false"
   UnhideWhenUsed="false" Name="Light List Accent 5"/>
  <w:LsdException Locked="false" Priority="62" SemiHidden="false"
   UnhideWhenUsed="false" Name="Light Grid Accent 5"/>
  <w:LsdException Locked="false" Priority="63" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Shading 1 Accent 5"/>
  <w:LsdException Locked="false" Priority="64" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Shading 2 Accent 5"/>
  <w:LsdException Locked="false" Priority="65" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium List 1 Accent 5"/>
  <w:LsdException Locked="false" Priority="66" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium List 2 Accent 5"/>
  <w:LsdException Locked="false" Priority="67" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Grid 1 Accent 5"/>
  <w:LsdException Locked="false" Priority="68" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Grid 2 Accent 5"/>
  <w:LsdException Locked="false" Priority="69" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Grid 3 Accent 5"/>
  <w:LsdException Locked="false" Priority="70" SemiHidden="false"
   UnhideWhenUsed="false" Name="Dark List Accent 5"/>
  <w:LsdException Locked="false" Priority="71" SemiHidden="false"
   UnhideWhenUsed="false" Name="Colorful Shading Accent 5"/>
  <w:LsdException Locked="false" Priority="72" SemiHidden="false"
   UnhideWhenUsed="false" Name="Colorful List Accent 5"/>
  <w:LsdException Locked="false" Priority="73" SemiHidden="false"
   UnhideWhenUsed="false" Name="Colorful Grid Accent 5"/>
  <w:LsdException Locked="false" Priority="60" SemiHidden="false"
   UnhideWhenUsed="false" Name="Light Shading Accent 6"/>
  <w:LsdException Locked="false" Priority="61" SemiHidden="false"
   UnhideWhenUsed="false" Name="Light List Accent 6"/>
  <w:LsdException Locked="false" Priority="62" SemiHidden="false"
   UnhideWhenUsed="false" Name="Light Grid Accent 6"/>
  <w:LsdException Locked="false" Priority="63" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Shading 1 Accent 6"/>
  <w:LsdException Locked="false" Priority="64" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Shading 2 Accent 6"/>
  <w:LsdException Locked="false" Priority="65" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium List 1 Accent 6"/>
  <w:LsdException Locked="false" Priority="66" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium List 2 Accent 6"/>
  <w:LsdException Locked="false" Priority="67" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Grid 1 Accent 6"/>
  <w:LsdException Locked="false" Priority="68" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Grid 2 Accent 6"/>
  <w:LsdException Locked="false" Priority="69" SemiHidden="false"
   UnhideWhenUsed="false" Name="Medium Grid 3 Accent 6"/>
  <w:LsdException Locked="false" Priority="70" SemiHidden="false"
   UnhideWhenUsed="false" Name="Dark List Accent 6"/>
  <w:LsdException Locked="false" Priority="71" SemiHidden="false"
   UnhideWhenUsed="false" Name="Colorful Shading Accent 6"/>
  <w:LsdException Locked="false" Priority="72" SemiHidden="false"
   UnhideWhenUsed="false" Name="Colorful List Accent 6"/>
  <w:LsdException Locked="false" Priority="73" SemiHidden="false"
   UnhideWhenUsed="false" Name="Colorful Grid Accent 6"/>
  <w:LsdException Locked="false" Priority="19" SemiHidden="false"
   UnhideWhenUsed="false" QFormat="true" Name="Subtle Emphasis"/>
  <w:LsdException Locked="false" Priority="21" SemiHidden="false"
   UnhideWhenUsed="false" QFormat="true" Name="Intense Emphasis"/>
  <w:LsdException Locked="false" Priority="31" SemiHidden="false"
   UnhideWhenUsed="false" QFormat="true" Name="Subtle Reference"/>
  <w:LsdException Locked="false" Priority="32" SemiHidden="false"
   UnhideWhenUsed="false" QFormat="true" Name="Intense Reference"/>
  <w:LsdException Locked="false" Priority="33" SemiHidden="false"
   UnhideWhenUsed="false" QFormat="true" Name="Book Title"/>
  <w:LsdException Locked="false" Priority="37" Name="Bibliography"/>
  <w:LsdException Locked="false" Priority="39" QFormat="true" Name="TOC Heading"/>
 </w:LatentStyles>
</xml><![endif]--> </p>
<p>本篇介绍groovy 的MetaClasses ，MetaClass 是Groovy 动态编程比较重要的组成。</p>
<p>(以下出现的代码片段是在groovy1.5.3测试通过，希望各位可以运行之)。</p>
<p>&nbsp;</p>
<p>1.MetaClass</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; groovy中出现的每个类都有其对应的MetaClass。MetaClas是一个接口，该接口扩展了MetaObjectProtocol接口，这就是我们通常所说的MOP协议了。</p>
<p>MetaClass的实现类主要有&nbsp; </p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><img src="../../../upload/picture/pic/17445/6c3caa48-8d6c-31c4-b19a-3164052c9d00.jpg" height="133" alt="" width="254" />
</p>
<p>MetaClassImpl 是通用的实现类。ClosureMetaClass是闭包类特有的MetaClass。ExpandoMetaClass是用户扩展groovy类行为时用到的MetaClass</p>
<p>&nbsp;</p>
<pre name="code" class="java">println 'first:---&gt; '+'test'.metaClass

println 'String.metaClass:---&gt; '+String.metaClass

println 'after String.metaClass:---&gt;  '+'test'.metaClass</pre>
<p>&nbsp;</p>
<div class="quote_title"> 执行结果为</div>
<div class="quote_div">first:---&gt; groovy.lang.MetaClassImpl@183f74d[class java.lang.String]<br />
String.metaClass:---&gt; groovy.lang.ExpandoMetaClass@8a0d5d[class java.lang.String]<br />
after String.metaClass:---&gt;&nbsp; groovy.lang.ExpandoMetaClass@8a0d5d[class java.lang.String]</div>
<p>&nbsp;对于这样的结果你是不是会感觉到奇怪呢？</p>
<p>下面我将结合Groovy实现代码来解释这个过程</p>
<p><strong>第一句脚本</strong>
通过String实例对象来获得，Groovy为其初始化的groovy.lang.MetaClassImpl@183f74d[class java.lang.String]对象。这个对象将在MetaClassRegistryImpl中和String类关联起来。也就是注册了String.class和</p>
<p>groovy.lang.MetaClassImpl的对象关系。</p>
<p><strong>第二句脚本</strong>
通过String类去访问 metaClass对象，不过这一次是调用了类DefaultGroovyMethods中的方法</p>
<p>&nbsp;</p>
<pre name="code" class="java">    /**
     * Adds a &quot;metaClass&quot; property to all class objects so you can use the syntax
     * &lt;code&gt;String.metaClass.myMethod = { println &quot;foo&quot; }&lt;/code&gt;
     *
     * @param c The java.lang.Class instance
     * @return An MetaClass instance
     */
    public static MetaClass getMetaClass(Class c) {
        MetaClassRegistry metaClassRegistry = GroovySystem.getMetaClassRegistry();
        MetaClass mc = metaClassRegistry.getMetaClass(c);
        if (mc instanceof ExpandoMetaClass
                || mc instanceof DelegatingMetaClass &amp;&amp; ((DelegatingMetaClass) mc).getAdaptee() instanceof ExpandoMetaClass)
            return mc;
        else {
            MetaClass emc = ExpandoMetaClassCreationHandle.instance.create(c, metaClassRegistry);
            emc.initialize();
            metaClassRegistry.setMetaClass(c, emc);//并且在metaClassRegistry中注册
            return emc;
        }
    }</pre>
<p>&nbsp;第三句脚本又重新通过String实例对象来获得了，但这一次得到的是groovy.lang.ExpandoMetaClass@8a0d5d，这是因为第二句话中对String和其MetaClass对象进行了重新注册。</p>
<p>自此以后系统中所有的String对象的MetaClass对象都一直市是ExpandoMetaClass对象实例。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>由于我们举的String例子有点特殊</p>
<p>我们看看对于自定义类的例子</p>
<pre name="code" class="java">class Foo{
	
}
def f1 = new Foo();
println f1.metaClass

println Foo.metaClass

println f1.metaClass

def f2 = new Foo()
println f2.metaClass</pre>
<p>&nbsp;结果是不是又不一样了？</p>
<p>f1对象的metaClass是被缓存了，只有在调用过</p>
<pre name="code" class="java">Foo.metaClass
</pre>
<p>&nbsp;之后，new出来的对象才会使用ExpandoMetaClass</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://grails.group.javaeye.com/group/blog/212082#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 06 Jul 2008 18:11:46 +0800</pubDate>
        <link>http://grails.group.javaeye.com/group/blog/212082</link>
        <guid>http://grails.group.javaeye.com/group/blog/212082</guid>
      </item>
      <item>
        <title>grails 根据数据库自动生产 domains</title>
        <author>dellsoft</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://dellsoft.javaeye.com">dellsoft</a>&nbsp;
          链接：<a href="http://grails.group.javaeye.com/group/blog/211729" style="color:red;">http://grails.group.javaeye.com/group/blog/211729</a>&nbsp;
          发表时间: 2008年07月04日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          GenerateDataabase.groovy<br /><pre name="code" class="java">
import java.lang.reflect.Method
import com.pansoft.extjs.DbunitDatabaseTemplateGenerator
import java.sql.Connection
import java.sql.DriverManager

/*
* Copyright 2004-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
 * Gant script that handles the creation of domain classes from an existing database
 *
 * @author dellsoft
 *
 * @since 1.0
 */

grailsAppName = ""

Ant.property(environment: "env")
grailsHome = Ant.antProject.properties."env.GRAILS_HOME"

includeTargets &lt;&lt; new File("${grailsHome}/scripts/Compile.groovy")

//pluginHome = new File("./plugins").listFiles().find {
//    it.name.startsWith('dbmapper-')
//}

target('default': "Generates code for all the domain classes in the database") {
    depends(promptForTableName,generateDomainClasses)
}

target(promptForTableName: "指定表名----") {
    if (!args) {
        Ant.input(addProperty: "artifact.name", message: "请输入表名:\nALL --代表所有")
        args = Ant.antProject.properties."artifact.name"
    }
}

target('generateDomainClasses': "Generate for all all the domain classes in the database") {
    profile("compiling config") {
        compile()
    }

    profile("creating config object") {
        ClassLoader contextLoader = Thread.currentThread().getContextClassLoader()
        classLoader = new URLClassLoader([classesDir.toURL()] as URL[], contextLoader)
        def configSlurper = new ConfigSlurper(grailsEnv)
        def configFile = new File("${basedir}/grails-app/conf/Config.groovy")
        if (configFile.exists()) {
            try {

                config = configSlurper.parse(classLoader.loadClass("Config"))
                config.setConfigFile(configFile.toURL())
            }
            catch (Exception e) {
                e.printStackTrace()

                event("StatusFinal", ["Failed to compile configuration file ${configFile}: ${e.message}"])
                exit(1)
            }

        }
        def dataSourceFile = new File("${basedir}/grails-app/conf/DataSource.groovy")
        if (dataSourceFile.exists()) {
            try {
                def dataSourceConfig = configSlurper.parse(classLoader.loadClass("DataSource"))
                config.merge(dataSourceConfig)
            }
            catch (Exception e) {
                e.printStackTrace()

                event("StatusFinal", ["Failed to compile data source file $dataSourceFile: ${e.message}"])
                exit(1)
            }
        }
        classLoader = contextLoader;
    }

    profile("generate the classes") {
        def username = config.dataSource.username
        def password = config.dataSource.password
        def databaseUrl = config.dataSource.url
        def driver = config.dataSource.driverClassName
        def sqlType
        def tableName = args
        if (driver.indexOf("sybase", 1) > 0) {
            sqlType = "sybase"
        } else if (driver.indexOf("mysql", 1) > 0) {
            sqlType = "mysql"
        } else if (driver.indexOf("oracle", 1) > 0) {
            sqlType = "oracle"
        } else if (driver.indexOf("hsql", 1) > 0) {
            sqlType = "hsql"
        }
        try {
            Class.forName(driver)

            Connection connection = DriverManager.getConnection(databaseUrl, username, password)
            connection.setAutoCommit true
            def generator = new DbunitDatabaseTemplateGenerator()
            println("tableName="+Arrays.asList(tableName).toString())
            println("tableName="+tableName)
            generator.generateDomainClasses(connection,sqlType,'','.',Arrays.asList(tableName))
            println("sqlType="+sqlType)

        } catch (Exception e) {
            e.printStackTrace()

            event("StatusFinal", ["Failed to generate domain classes: ${e.message}"])
            exit(1)
        }
        println("Successfully generated domain classes")
    }
}

</pre><br /><br />DbunitDatabaseTemplateGenerator.groovy<br /><br /><pre name="code" class="java">
package com.pansoft.extjs

import org.codehaus.groovy.grails.scaffolding.DefaultGrailsTemplateGenerator
import org.codehaus.groovy.grails.commons.GrailsDomainClass
import groovy.text.*;
import org.apache.commons.logging.Log;
import org.springframework.core.io.*
import org.apache.commons.logging.LogFactory;
import org.codehaus.groovy.grails.commons.GrailsDomainClass;
import org.codehaus.groovy.grails.commons.GrailsApplication;
import org.codehaus.groovy.grails.scaffolding.GrailsTemplateGenerator;
import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU
import org.codehaus.groovy.grails.commons.ApplicationHolder
import java.sql.Connection
import org.dbunit.database.IDatabaseConnection
import org.dbunit.ext.mssql.MsSqlConnection
import org.dbunit.dataset.IDataSet
import org.dbunit.ext.mysql.MySqlConnection
import org.dbunit.ext.oracle.OracleConnection
import org.dbunit.ext.hsqldb.HsqldbConnection
import org.dbunit.dataset.ITableMetaData
import org.dbunit.database.DatabaseConnection;
import org.dbunit.dataset.datatype.*
import java.sql.DatabaseMetaData
import java.sql.ResultSet;
/**
 * Created by IntelliJ IDEA.
 * User: dellsoft
 * Date: 2008-5-21
 * Time: 10:18:13
 * To change this template use File | Settings | File Templates.
 */
class DbunitDatabaseTemplateGenerator extends DefaultGrailsTemplateGenerator {
    static final Log Dbunitlog = LogFactory.getLog(DbunitDatabaseTemplateGenerator.class);

    public IDatabaseConnection conn
    public IDataSet dataSet
//    public String[] tables
    def tables = []
    public DatabaseMetaData databaseMetaData
    def indexColumns = []
    public ResultSet resultSet

    // 定义对应的数据类型
    def dataType = {column ->
//        def column = property
//        def cp = domainClass.constrainedProperties[property.name]

        if (!renderEditorTemplate) {
            // create template once for performance
            def templateText = getTemplateText("dataType.template")
            renderEditorTemplate = engine.createTemplate(templateText)
            Dbunitlog.info("templateText=" + templateText)
        }


        def binding = [column: column]
        Dbunitlog.info("binding=" + binding)
        return renderEditorTemplate.make(binding).toString()
    }

//    public DbunitDatabaseTemplateGenerator(Connection con,String sqlType) {
//
//
//
//    }

    // get the tables from the dataset
    public void generateDomainClasses(Connection conn, String sqlType, String pkg, String destDir, List tableName) {
        switch (sqlType) {
            case 'sybase': this.conn = new MsSqlConnection(conn, null)
                break
            case 'mysql': this.conn = new MySqlConnection(conn, null)
                break
            case 'oracle': this.conn = new OracleConnection(conn, null)
                break
            case 'hsql': this.conn = new HsqldbConnection(conn, null)
                break

        }

        dataSet = this.conn.createDataSet()
        tables = Arrays.asList(dataSet.getTableNames())
        def tableTmp = []
        if (tableName.size() > 0) {
            tableName.each {
                tableTmp &lt;&lt; it.toLowerCase()
            }
        }

        if (tableTmp.contains("all")) {

        } else {
            def tmp = [] 
            tmp = tables.findAll {
                tableTmp.contains(it.toLowerCase())
            }.asList()
            tables = tmp
        }

        databaseMetaData = this.conn.getConnection().getMetaData()
        tables.each {
            indexColumns.clear()
            resultSet = databaseMetaData.getIndexInfo(null, this.conn.schema, it, true, false)
//            resultSet = databaseMetaData.getBestRowIdentifier(null, this.conn.schema, it, DatabaseMetaData.bestRowSession, true)
            while (resultSet.next()) {
//                indexColumns['table'] = resultSet.getString(3)
//                indexColumns['unique'] = resultSet.getString(6)
//                indexColumns['type'] = resultSet.getString(7)
                if (resultSet.getString(9) != 'null' && !resultSet.getString(9).is(null)) {
                    indexColumns &lt;&lt; resultSet.getString(9)
                }

            }
            generateDomain(dataSet.getTableMetaData(it), pkg, destDir)
        }
        this.conn.close()
    }
    // generate domains from the tables
    public void generateDomain(ITableMetaData tableMetaData, String pkg, String destdir) {
        if (!destdir)
            throw new IllegalArgumentException("Argument [destdir] not specified")

        if (tableMetaData.tableName) {
            Dbunitlog.info("Domain generated at ${tableMetaData.tableName}")
            System.out.println("tableName=" + tableMetaData.tableName)
//            def fullName = domainClass.fullName
//            def pkg = ""
//            def pos = fullName.lastIndexOf('.')
//            if (pos != -1) {
//                // Package name with trailing '.'
//                pkg = fullName[0..pos]
//            }

            def destFile = new File("${destdir}/grails-app/domain/${tableMetaData.tableName[0] + tableMetaData.tableName[1..-1].toLowerCase()}.groovy")
            if (canWrite(destFile)) {
                destFile.parentFile.mkdirs()

                destFile.withWriter {w ->
                    generateDomain(tableMetaData, w)
                }

                Dbunitlog.info("Domain generated at ${destFile}")
            }
        }
    }

    public void generateDomain(ITableMetaData tableMetaData, Writer out) {
        def templateText = getTemplateText("Domain.groovy")

        def binding = [
                tableName: tableMetaData.tableName[0] + tableMetaData.tableName[1..-1].toLowerCase(),
                columns: tableMetaData.columns,
                primaryKeys: tableMetaData.primaryKeys,
                indexColumns: indexColumns,
                dataType: dataType,
                comparator: org.codehaus.groovy.grails.scaffolding.DomainClassPropertyComparator.class]

        def t = engine.createTemplate(templateText)
        t.make(binding).writeTo(out)
    }



    private canWrite(testFile) {
        if (!overwrite && testFile.exists()) {
            try {
                ant.input(message: "File ${testFile} already exists. Overwrite?", "y,n,a", addproperty: "overwrite.${testFile.name}")
                overwrite = (ant.antProject.properties."overwrite.${testFile.name}" == "a") ? true : overwrite
                return overwrite || ((ant.antProject.properties."overwrite.${testFile.name}" == "y") ? true : false)
            } catch (Exception e) {
                // failure to read from standard in means we're probably running from an automation tool like a build server
                return true
            }
        }
        return true
    }

    private getTemplateText(String template) {
        def application = ApplicationHolder.getApplication()
        // first check for presence of template in application
        if (resourceLoader && application?.warDeployed) {
            return resourceLoader.getResource("/WEB-INF/templates/scaffolding/${template}").inputStream.text
        }
        else {
            def templateFile = "${basedir}/src/templates/scaffolding/${template}"
            if (!new File(templateFile).exists()) {
                // template not found in application, use default template
                def ant = new AntBuilder()
                ant.property(environment: "env")
                def grailsHome = ant.antProject.properties."env.GRAILS_HOME"
                templateFile = "${grailsHome}/src/grails/templates/scaffolding/${template}"
            }
            return new File(templateFile).getText()
        }
    }


}
</pre><br /><br />domain.groovy 模板<br /><pre name="code" class="java">
&lt;% import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor as Events %>
&lt;% import org.dbunit.dataset.datatype.* %>
class ${tableName} {
&lt;%
    def excludedColumns = ['id', 'version']
    //out put the column
    String omitPrefix = "F_"
    def outColumns = []
    def primaryFields = []
    def mappingFields = [:]
    def constraintsFields = [:]
    def idColumn = ["F_ID"]
    def isUseIdColumn = true
    def isUseVersionColumn = true
    outColumns = columns.findAll {!excludedColumns.contains(it.columnName)}
    outColumns.each {p ->
        def outName
        outName = getOmitPrefixColumn(p.columnName,omitPrefix)
        mappingFields[outName] = p.columnName
        constraintsFields[outName] = p.nullable
%>
    ${dataType(p)} ${outName}
&lt;%
    }
    primaryKeys.each {p ->
        primaryFields &lt;&lt; getOmitPrefixColumn(p.columnName,omitPrefix)
    }

    if (primaryFields.isEmpty()) {
        primaryFields = indexColumns
    }

    public String getOmitPrefixColumn(String orignalColumn,String omitPrefixString) {
        String  omitPrefixColumn
        if (orignalColumn.contains(omitPrefixString)){
            omitPrefixColumn = orignalColumn[omitPrefixString.length()..-1].toLowerCase()
        }else {
            omitPrefixColumn = orignalColumn.toLowerCase()
        }
        return   omitPrefixColumn
    }
    if (isUseIdColumn) {
        primaryFields = idColumn
    }


%>
    static mapping = {
       // table '${tableName}'
      &lt;% if ( !isUseVersionColumn ){ %>
        version false
       &lt;% } %>
      //  id composite: ['${primaryFields.join(', ')}']
&lt;%
    mappingFields.each {key,value ->
%>
        ${key} column: '${value}'
&lt;%
    }
%>                                                      
    }

    static constraints = {
&lt;%
    constraintsFields.each {column ->
    if ("${column.value}" == "noNulls") {
%>
        ${column.key} (nullable: false)
&lt;%
        }
    }
%>
    }
}
</pre>
          <br/>
          <span style="color:red;">
            <a href="http://grails.group.javaeye.com/group/blog/211729#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 04 Jul 2008 17:25:27 +0800</pubDate>
        <link>http://grails.group.javaeye.com/group/blog/211729</link>
        <guid>http://grails.group.javaeye.com/group/blog/211729</guid>
      </item>
      <item>
        <title>grails 导出 excel</title>
        <author>dellsoft</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://dellsoft.javaeye.com">dellsoft</a>&nbsp;
          链接：<a href="http://grails.group.javaeye.com/group/blog/211728" style="color:red;">http://grails.group.javaeye.com/group/blog/211728</a>&nbsp;
          发表时间: 2008年07月04日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          用 poi 来导出 excel 文件<br /><br /><pre name="code" class="java">
import org.codehaus.groovy.grails.commons.*
import org.apache.poi.hssf.usermodel.HSSFWorkbook
import org.apache.poi.hssf.usermodel.HSSFSheet
import org.apache.poi.hssf.usermodel.HSSFRow
import org.apache.poi.hssf.usermodel.HSSFCell
import org.codehaus.groovy.grails.commons.GrailsDomainClass
import org.codehaus.groovy.grails.web.converters.ConverterUtil
import org.springframework.web.servlet.support.RequestContextUtils as RCU
import org.codehaus.groovy.grails.scaffolding.DomainClassPropertyComparator;
import org.springframework.context.MessageSource
import org.apache.poi.hssf.usermodel.HSSFCellStyle
import org.apache.poi.hssf.usermodel.HSSFFont
import org.apache.poi.hssf.util.HSSFColor;

class XlsExportService {

//    def messageSource
    MessageSource messageSource
    boolean transactional = true
//    def config = ConfigurationHolder.config
//    def domainName
    def xlsExport(out, request, domain, datas) {
        def excludedProps = ['id', 'version']
        def column = []
        def titles = []
        def outProperties
        def locale = RCU.getLocale(request)
//        def text
        def args
        def domainName = domain.toLowerCase()
        GrailsDomainClass domainClass = ConverterUtil.getDomainClass(domain)
        if (domainClass != null) {
            outProperties = domainClass.properties.findAll {!excludedProps.contains(it.name)}
        }
        Collections.sort(outProperties, new DomainClassPropertyComparator(domainClass))
        outProperties.each {
            column &lt;&lt; "${it.name}"
            def text = messageSource.getMessage(
                    "${domainName}.${it.name}".toString(),
                    args == null ? null : args.toArray(),
                    "${domainName}.${it.name}".toString(),
                    locale)
            titles &lt;&lt; text
        }
        HSSFWorkbook wb = new HSSFWorkbook();
        HSSFSheet sheet = wb.createSheet("new sheet");
        HSSFRow row
        HSSFCell cell
        HSSFCellStyle style = wb.createCellStyle()
        HSSFFont font   =   wb.createFont()
        font.setFontHeightInPoints((short)12)
        font.setFontName("宋体")
        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD) 
        style.setFont(font)
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER)
        style.setFillBackgroundColor(HSSFColor.ORANGE.index)
//        style.setFillPattern(HSSFCellStyle.)
        // set the title
        row = sheet.createRow((short) 0);
        titles.eachWithIndex {title, i ->
            cell = row.createCell((short) (i));
            cell.setCellStyle(style)
            cell.setCellValue(title);
        }

        // set the data
        datas.eachWithIndex {data, i ->
            row = sheet.createRow((short) (i+1));
            column.eachWithIndex {p, j ->
                row.createCell((short) (j)).setCellValue(data."${p}");

            }

        }

        // Write the output to a file
        wb.write(out);
        out.close()

    }


}

</pre><br />在你的 domaincontroller 中加入<br /><br /><pre name="code" class="java">
 def exportXls = {
//        def excludedProps = ['id', 'version']
//        def column = []
//        def titles = []
//        def outProperties = []
//        GrailsDomainClass domainClass = ConverterUtil.getDomainClass("Person");
//        if (domainClass != null) {
//            domainClass.persistentProperties.each {p ->
//                outProperties &lt;&lt; p.name
//            };
//
//        }
//        outProperties.each {
//            column &lt;&lt; "${it}"
//            titles &lt;&lt; message(code: "person.${it}")
//        }
        response.setHeader("Content-disposition", "attachment; filename=person.xls")
        response.setContentType("application/vnd.ms-excel")
//        ServletOutputStream f = response.getOutputStream();
        xlsExportService.xlsExport(response.outputStream, request,"Person", Person.list())
//        render(contextType:"application/vnd.ms-excel")


    }
</pre><br /><br />这个好处就是导出的表头信息通过 properties来获取！
          <br/>
          <span style="color:red;">
            <a href="http://grails.group.javaeye.com/group/blog/211728#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 04 Jul 2008 17:21:36 +0800</pubDate>
        <link>http://grails.group.javaeye.com/group/blog/211728</link>
        <guid>http://grails.group.javaeye.com/group/blog/211728</guid>
      </item>
      <item>
        <title>grails war 包定制</title>
        <author>dellsoft</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://dellsoft.javaeye.com">dellsoft</a>&nbsp;
          链接：<a href="http://grails.group.javaeye.com/group/blog/211726" style="color:red;">http://grails.group.javaeye.com/group/blog/211726</a>&nbsp;
          发表时间: 2008年07月04日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          在config.groovy 下面配置<br /><br />grails.war.resources = {stagingDir -><br />    copy(todir: "${stagingDir}/WEB-INF/classes/grails-app/yourDir") {<br />        fileset(dir:"grails-app/YourDir")<br />    }<br />}
          <br/>
          <span style="color:red;">
            <a href="http://grails.group.javaeye.com/group/blog/211726#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 04 Jul 2008 17:18:04 +0800</pubDate>
        <link>http://grails.group.javaeye.com/group/blog/211726</link>
        <guid>http://grails.group.javaeye.com/group/blog/211726</guid>
      </item>
      <item>
        <title>grails datasource 中配置数据源用户名称和密码 加密</title>
        <author>dellsoft</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://dellsoft.javaeye.com">dellsoft</a>&nbsp;
          链接：<a href="http://grails.group.javaeye.com/group/blog/211724" style="color:red;">http://grails.group.javaeye.com/group/blog/211724</a>&nbsp;
          发表时间: 2008年07月04日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          在datasource.groovy<br />password = YourClass.decode(加密后的密码)<br /><br />提前用YourClass.encode(原始密码)获得加密后的密码
          <br/>
          <span style="color:red;">
            <a href="http://grails.group.javaeye.com/group/blog/211724#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 04 Jul 2008 17:16:41 +0800</pubDate>
        <link>http://grails.group.javaeye.com/group/blog/211724</link>
        <guid>http://grails.group.javaeye.com/group/blog/211724</guid>
      </item>
      <item>
        <title>grails  自定义 validator</title>
        <author>dellsoft</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://dellsoft.javaeye.com">dellsoft</a>&nbsp;
          链接：<a href="http://grails.group.javaeye.com/group/blog/211702" style="color:red;">http://grails.group.javaeye.com/group/blog/211702</a>&nbsp;
          发表时间: 2008年07月04日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <a href="http://www.zorched.net/2008/01/25/build-a-custom-validator-in-grails-with-a-plugin/" target="_blank">http://www.zorched.net/2008/01/25/build-a-custom-validator-in-grails-with-a-plugin/</a>
          <br/>
          <span style="color:red;">
            <a href="http://grails.group.javaeye.com/group/blog/211702#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 04 Jul 2008 17:05:13 +0800</pubDate>
        <link>http://grails.group.javaeye.com/group/blog/211702</link>
        <guid>http://grails.group.javaeye.com/group/blog/211702</guid>
      </item>
      <item>
        <title>grails中使用fckeditor,配置代码高亮</title>
        <author>sword721</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://sword721.javaeye.com">sword721</a>&nbsp;
          链接：<a href="http://grails.group.javaeye.com/group/blog/211432" style="color:red;">http://grails.group.javaeye.com/group/blog/211432</a>&nbsp;
          发表时间: 2008年07月04日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp; 下载下面提供的压缩包,grails-fckeditor-0.6.zip.直接在命令行下输入:grails install-plugin &quot;插件所在的路径&quot;/grails-fckeditor-0.6.zip.安装成功之后我们就可以直接使用了.</p>
<p>&nbsp;</p>
<pre name="code" class="html">&lt;fckeditor:editor id=&quot;content&quot; name=&quot;content&quot; width=&quot;600&quot; height=&quot;400&quot;&gt;
       ${article?.content?.encodeAsHTML()}
&lt;/fckeditor:editor&gt;</pre>
<p>&nbsp;</p>
<p>还可以为fckeditor加入代码高亮显示,我用的是SyntaxHighlighter.</p>
<p>使用方法：<br />
            1、在您的FCKeditor的配置文件中（一般为fckconfig.js或custom.config.js）<br />
            配置其中的FCKConfig.ToolbarSets，添加HighLighter。<br />
            如：<br />
            &nbsp;&nbsp;&nbsp; FCKConfig.ToolbarSets[&quot;review&quot;] = [<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
['HighLighter','Bold','Italic','Underline','StrikeThrough','Link','Unlink','Image','Rule','Smiley','TextColor','BGColor']<br />
            &nbsp;&nbsp;&nbsp; ];<br />
            当然，你可以放到别的工具栏，不过记得注意大小写。<br />
            &nbsp;<br />
            2、根据你指定的plugin目录，注册plugin<br />
            如：<br />
            &nbsp;&nbsp;&nbsp; // 代码语法高亮插件<br />
            &nbsp;&nbsp;&nbsp; FCKConfig.Plugins.Add( 'highlighter', 'zh-cn,en' ) ;<br />
            <br />
            3、OK,你会发现你的FCK工具栏的图片多了一个带有&quot;ab&quot;字母，黄底的图标。你就可以使用语法高亮显示功能了。</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://grails.group.javaeye.com/group/blog/211432#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 04 Jul 2008 11:50:11 +0800</pubDate>
        <link>http://grails.group.javaeye.com/group/blog/211432</link>
        <guid>http://grails.group.javaeye.com/group/blog/211432</guid>
      </item>
      <item>
        <title>Groovy on Grails 初探</title>
        <author>znsan</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://znsan.javaeye.com">znsan</a>&nbsp;
          链接：<a href="http://grails.group.javaeye.com/group/blog/211301" style="color:red;">http://grails.group.javaeye.com/group/blog/211301</a>&nbsp;
          发表时间: 2008年07月04日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><span style="font-size: small;">此文仅为本人初次学习和实践G&amp;G的心得体会以及开发经验的记录，旨在将我的感受保留下来以备未来查阅。欢迎大家指正和补充：）</span>
</p>
<p><span style="font-size: small;">一、Domain Class<br />
</span>
</p>
<p><span style="font-size: small;">1. 对于一个领域类对应一个表的情况最好解决，每一个字段对应一列，是最爽的形式</span>
</p>
<p><span style="font-size: small;">2. 每个领域类最好重写toString()方法，目的在于关联的显示时展现有意义的文字而不是简单的ID</span>
</p>
<p><span style="font-size: small;">3. static constraints = {}有两个作用，一是规定了字段在页面中的顺序；另外就是数据约束在这里定义。PS：一定要保证拼写正确，我就因为拼写错误导师运行不成功，郁闷了很久才找到错误原因。</span>
</p>
<p><span style="font-size: small;">4. 在字段定义是一定要保证其不是数据库中的关键字！！这点很重要，我已经两次在这方面出错了。一次是desc，一次是order</span>
</p>
<p><span style="font-size: small;">5. 在数据验证中，blank是针对String类型的不为空，而其他类型不为空则要用nullable，如Integer。常用的还有maxSize，也是针对String类型的长度。如无必需最好不要大于255，若大于则数据库中类型不是Varchar了。</span>
</p>
<p><span style="font-size: small;">6. 在一对多关系中，一方要有hasMany闭包，这样可以在内容显示时包括多方的链接；多方中belongsTo是可选的，如果加上则会被级联删除。</span>
</p>
<p><span style="font-size: small;">7. static mapping 闭包可以修改默认的字段与表的对应方式，尤其在处理遗留数据库时有用</span>
</p>
<p>&nbsp;</p>
<p><span style="font-size: small;">二、数据库访问</span>
</p>
<p><span style="font-size: small;">1. 数据源配置：在grails-app/conf/DataSource.groovy里配置，<code>dbCreate</code>
 的值在不同的环境下会产生不同的行为。它是底层的 <code>hibernate.hbm2ddl.auto</code>
 设置的别名，负责指定 Hibernate 在幕后如何管理表。将
        <code>dbCreate</code>
 设为 <code>create-drop</code>
<code>create</code>
，那么
        Hibernate 会在需要的时候创建新表和修改现有表，但是重新启动之间的所有记录都会被删除。<code>production</code>
 模式的默认值 &mdash;
                <code>update</code>
                &mdash; 会在重新启动之间保持所有数据，也会在需要的时候创建或修改表。</span>
，就是告诉在启动的时候创建表，在关闭的时候删除表。如果将值改为 </p>
<p><span style="font-size: small;">2. 注意要把访问数据的jar包拷贝到lib目录中。</span>
</p>
<p><span style="font-size: small;">3. 可添加自定义环境，如beta，同development等设置，在启动程序时<code>grails -Dgrails.env=beta run-app</code>
</span>
</p>
<p><span style="font-size: small;">4. 数据库模式还是要先建立好的，Grails只能修改表而不是数据库</span>
</p>
<p><span style="font-size: small;">5. 一般的run-app使用development数据配置，打成war包后使用production配置。要保证lib中有数据访问驱动</span>
</p>
<p><span style="font-size: small;">6. 数据库连接字符串要写对格式，如mysql的：jdbc:mysql://localhost:3306/trip</span>
</p>
<p><span style="font-size: small;"><br />
</span>
</p>
<p><span style="font-size: small;">三、页面修改</span>
</p>
<p><span style="font-size: small;">1. 页面跟普通JSP页面没有太多区别，一般内置标签&lt;g:**&gt;无需导入就可直接使用，自己编写的Tag只要按照规约放在指定的目录下即可直接使用。</span>
</p>
<p><span style="font-size: small;">2. 最爽的一点是页面修改无需重启服务器，因而修改后直接刷新就能看到效果</span></p>
<p><span style="font-size: small;">3. 一般生成的页面上都有ID这个字段，最好都删去避免出错</span>
</p>
<p>&nbsp;</p>
<p><span style="font-size: small;">四、控制器及业务逻辑</span>
</p>
<p><span style="font-size: small;">1. 有两种默认控制器执行，一是转到index闭包；另外就是直接指定</span>
</p>
<p><span style="font-size: small;">2. 不是所有闭包都要有对应的视图，可以转到任何试图，render是渲染的意思，redirect是重定向</span>
。<span style="font-size: small;">这两种方式都可以用flash.message来显示提示信息</span>
</p>
<p><span style="font-size: small;">3. 可以直接使用Java语言中的类库或Groovy语言。在访问数据库方面还是Groovy比较方便，例子如下：</span>
</p>
<p><span style="font-size: small;">&nbsp;&nbsp;&nbsp; 首先要import groovy.sql.Sql</span>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; def db = Sql.newInstance(DB,ID,PASSWORD,DRIVER)<br />
&nbsp;&nbsp;&nbsp; &nbsp; def result = db.execute(&quot;DELETE FROM member WHERE id=${m.homeId}&quot;)</p>
<p><span style="font-size: small;">4. 保持Domain时hasErrors()只是检查对象是否构造无误，而save()才是真正进行约束检查</span></p>
<p><span style="font-size: small;"><br />
</span>
</p>
<p><span style="font-size: small;">五、其他</span>
</p>
<p><span style="font-size: small;">1. 所有文件最好都用utf-8格式保存，这样能对中文友好支持！</span>
</p>
<p><span style="font-size: small;">2. i18n文件已经有多个语言版本，根据本机配置会自动选择，在中国就使用messages_zh_CN.properties</span>
</p>
<p><span style="font-size: small;">3. 如User中的username的非空提示就应为：User.username.blank = 用户名不能为空。无需自己进行本地转化，启动时系统会自动为你转换。具体参考官方文档</span></p>
<p><span style="font-size: small;"><br />
</span>
</p>
<p>version 1.1
</p>
<p><span style="font-size: small;">未完待续...</span>
</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://grails.group.javaeye.com/group/blog/211301#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 04 Jul 2008 03:21:06 +0800</pubDate>
        <link>http://grails.group.javaeye.com/group/blog/211301</link>
        <guid>http://grails.group.javaeye.com/group/blog/211301</guid>
      </item>
      <item>
        <title>jsecurity 资料</title>
        <author>dellsoft</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://dellsoft.javaeye.com">dellsoft</a>&nbsp;
          链接：<a href="http://grails.group.javaeye.com/group/blog/205028" style="color:red;">http://grails.group.javaeye.com/group/blog/205028</a>&nbsp;
          发表时间: 2008年06月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          今天看到一个好消息就是 jsecuirty，将要变成apache的一个工程了。<br />这将推动jsecurity的广泛应用，结束目前不温不火的局面。<br /><br />http://www.jsecurity.org/node/1049
          <br/>
          <span style="color:red;">
            <a href="http://grails.group.javaeye.com/group/blog/205028#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 18 Jun 2008 10:22:05 +0800</pubDate>
        <link>http://grails.group.javaeye.com/group/blog/205028</link>
        <guid>http://grails.group.javaeye.com/group/blog/205028</guid>
      </item>
      <item>
        <title>关于未来</title>
        <author>belmount</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://belmount.javaeye.com">belmount</a>&nbsp;
          链接：<a href="http://grails.group.javaeye.com/group/blog/204768" style="color:red;">http://grails.group.javaeye.com/group/blog/204768</a>&nbsp;
          发表时间: 2008年06月17日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          在很长的一段时间，我已经放弃了对Grails的研究。最近开始和项目中采用Grails开发过的开发人员讨论心得的时候，我发现Grails虽然文档比较整齐，但是从规模和社区支持而言它还是远远低于Ruby社区的。<br />当初Grails的起源就是希望在JVM上实现类似于ROR的框架。虽然在Grails之前，出现过Trails之类的框架，但是因为静态语言的局限性，他们的发展总是不尽人意。Grails的优势在于它使用的是动态语言Groovy,同时集成了各种流行的框架。性能上由于编译的原因，也比一般的ROR程序快一些。但从根本上而言，他还是死死的把自己绑在了Java这条船上。<br />从ROR来说，它的基础Ruby更为开放。最近看了infoq关于JRuby新版本的特性介绍的视频，至少在JVM上，我们已经看不到Groovy的优势。Groovy能做的所有事情,用Ruby语言在JVM上也能够实现。原来因为纯动态而造成的性能问题，JRuby也有编译后的版本提供。另外，通过JRuby，Ruby也能够访问各种已经存在的Java Class。那么，我要问问我自己，还有没有掌握Groovy的必要。从另一方面而言，只要ROR