`
Ivan_Pig
  • 浏览: 381914 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

使用Groovy on Grails实现Ruby on Rails15分钟创建的Blog

阅读更多
    事先说明,我对Ruby只懂个皮毛。而Rails则没有接触过。看了视频后,还是能看懂的,语法什么的大概都能猜到意思。现在学习Grails,所以想用Grails来实现看看。

    先分析下,视频里面所讲的Blog的内容。以Grails的名词来解释。(不知道Rails里面的专业术语。。。。)

1.首先是两个领域模型,Post和Comment。是一对多的关系。Post里面有title和body属性,不能为空。Comment里面持有Post的id以及body属性。
2.身份的验证。发布,编辑Post需要身份验证。
3.实现RSS浏览Post
4.回复Comment
5.AJAX实现动态显示添加的Comment

    下面就开始使用Grails来实现这个Blog。开发工具是Intellij Idea + Grails插件。

    首先,创建Blog项目,和创建Java项目是类似的。如果你爱用命令行那就敲命令吧。

    创建完了项目,那么就开始着手实现了,当然是先创建两个领域模型Post和Comment.
class Post {
    static hasMany = [comment:Comment]
    
    String title
    String body
}
class Comment {
    Post post
    String body
}

    如果使用过任何ORM框架,那么这段代码没有难理解的地方吧!

    静态的hasMany设置是个Groovy的hashmap:键是comment;值是Comment类.

    接着创建Post和Comment的CRUD.
新建两个Controller,GroovyController和CommentController。如下所示。

class PostController {
    def scaffold = Post
}
class CommentController {
    def scaffold = Comment
}


    def scaffold = ***的意思就是创建最基本的CRUD。这样你就可以运行项目了。看看效果。



    框框内就是两个Controller。首先看看PostController。在你点击了NewPost之后,你会立刻发现两个问题。Body在Title的上方,Body的输入区域是textfield,而一般应该是textarea。先不管这个,随便输入点信息进去,是没有问题的。说明目前基本流程对了,那么下面开始修改刚才说的问题,并给Title和Body加上不能为空的限制。其实排序和限制可以说是一样的东西。往下看。

打开Post领域模型。修改代码如下

class Post {
    static hasMany = [comment:Comment]
    
    String title
    String body

    static constraints = {
        title(maxLength:50,blank:false)
        body(blank:false)
    }
}

    这个闭包应该很好理解吧?title长度不能超过50,不能为空,body也不能为空。而排序也已经被完成了。Grails会按照限制里面的顺序来列出内容。但是这里需要重新启动服务。否则不会出先效果。重启服务器试试看吧。
    顺个便给Comment也加个限制。
class Comment {
    Post post
    String body

    static constraints = {
        post()
        body(blank:false)
    }
}

 
    这里对post没有限制,但是如果你想要post在body前面,那么需要这么写。
   
    接着修改页面显示。你需要general-all controller。我没有在Intellij Idea里面找到哪里可以做此操作(希望知道的告知一声,谢谢。)手动删除PostController和CommentController.使用命令行到项目的根路径下面。输入grails generate-all。在出现提示:Domain Class name not specified. Please enter:时,输入Post。结束以后再次输入grails generate-all,接着输入Comment。这样就可以了。

    现在你会发现两个Controller里面多了很多代码,不管这些。到views目录下面,找到post目录,里面会有四个gsp文件(类似jsp的东西,学过jsp,看gsp没障碍)。刚才出问题的是add.gsp。进入此页面。找到body,将input标签替换为textarea标签即可,这里有个问题,<textarea></textarea>需要这样写,否则会有问题。至少我这里是。
    
    接着就是身份验证了。
    视频里面是使用了一个filter来过滤的(看着是挺简单的)。也没写页面什么,迷惑。
    在Grails里面我是这么实现的!添加一个新的领域模型User来控制访问权限,登录后存放到session里面,然后编辑或创建的时候检查session。没有则转到登录页面。
    这里也和视频里面一样就不查数据库了,检验用户名和密码是否都为admin,是就登录,否则就还在登录页面。
    先建立User领域模型。然后generall-all。

class User {
    String userId
    String password

    static constraints = {
        userId(blank:false)
        password(minLength:6,blank:false)
    }
}


    接着手动的创建登录页面和添加action。
    这里的动作比较大一点。在UserController里面添加如下代码

def login = {
        if (request.method == "GET") {
            session.userId = null
            def userInstance = new User()
        }
        else {
            if(params.userId == "admin" && params.password == "admin"){
                def userInstance = new User(userId:params.userId,password:params.password)
                session.userId = userInstance.userId
                redirect(controller: 'post')
            }else {
                flash['message'] =
                    'Please enter a valid user ID and password'
            }
        }
    }

    如果登录成功则跳转到post控制器,否则打印错误信息。
    再在views目录下的user里面添加一个login.gsp,添加如下代码。

<html>
<head>
<meta http-equiv="Content-Type"
      content="text/html; charset=UTF-8"/>
<meta name="layout" content="main" />
<title>Log in</title>
</head>
<body>
<div class="body">
   <h1>Please log in</h1>
    <g:if test="${flash.message}">
        <div class="message">${flash.message}</div>
    </g:if>
    <g:hasErrors bean="${race}">
        <div class="errors">
           <g:renderErrors bean="${user}" as="list" />
        </div>
    </g:hasErrors>
    <g:form controller="user" method="post" >
        <div class="dialog">
        <table>
           <tr class='prop'>
               <td valign='top' class='name'>
                  <label for='userId'>User ID:</label>
               </td>
               <td valign='top' class='value '>
                  <input type="text" maxlength='8'
                         name='userId'
                         value='${user?.userId}'/>
               </td>
           </tr>
           <tr class='prop'>
               <td valign='top' class='name'>
                  <label for='password'>
                      Password:
                  </label>
               </td>
               <td valign='top' class='value '>
                  <input type="password" maxlength='8'
                         name='password'
                         value='${user?.password}'/>
               </td>
           </tr>
        </table>
        </div>
        <div class="buttons">
           <span class="button">
               <g:actionSubmit value="Log in" />
           </span>
        </div>
    </g:form>
 </div>
 </body>
 </html>


     现在登录就做好了,怎样把他给添加到流程里面去。这里需要一个Filter,在conf文件夹里面创建一个LoginFilters的groovy类,一定要以Filters结尾。
添加如下代码:
class LoginFilters {
    def filters = {
        loginCheck(controller: 'post', action: '*') {
            before = {
                if (!session.userId) {
                    if (actionName.equals('create')||actionName.equals('delete')||actionName.equals('update')||actionName.equals('edit')) {
                        redirect(controller: 'user', action: 'login')
                        return false
                    }
                }
            }
        }
    }
}

    作用就是,当post里面调用的是create,delete,edit或者update Action的时候,如果没有登录则跳转到登录页面。

    这样,权限就设置好了。再进行一下改进,因为这里只要登录成功后就会跳转到list页面,这肯定有问题,应该先记录用户要登录的页面,在登录成功后,再跳转到那个页面。

    修改LoginFilters,如下

class LoginFilters {
    def filters = {
        loginCheck(controller: 'post', action: '*') {
            before = {
                if (!session.userId) {
                    if (actionName.equals('create')||actionName.equals('delete')||actionName.equals('update')||actionName.equals('edit')) {
                        def originalRequestParams =[controller:controllerName,action:actionName]
                        originalRequestParams.putAll(params)
                        session.originalRequestParams = originalRequestParams

                        redirect(controller: 'user', action: 'login')
                        return false
                    }
                }
            }
        }
    }
}


    再修改下,UserController里面的login Action,如下

def login = {
        if (request.method == "GET") {
            session.userId = null
            def userInstance = new User()
        }
        else {
            if(params.userId == "admin" && params.password == "admin"){
                def userInstance = new User(userId:params.userId,password:params.password)
                session.userId = userInstance.userId

                def redirectParams =session.originalRequestParams ?session.originalRequestParams :[controller:'post']

                redirect(redirectParams)
            }else {
                flash['message'] =
                    'Please enter a valid user ID and password'
            }
        }
    }


    这样身份验证就完全添加好了。

    接着是RSS功能.

    Grails并没有对RSS或者Atom提供直接支持。你可以通过控制器render方法的XML能力来构造RSS或者ATOM。尽管如此,还是有一个Feeds 插件 (基于流行的 ROME 开发库)来为Grails提供RSS和Atom的生成器 (Grails参考手册13.3 )

    插件可以到http://plugins.grails.org/下载。
    或者使用命令行,到项目根路径下键入grails install-plugin feeds
    然后在,PostController里添加一个Action
def feed = {
            render(feedType:"rss", feedVersion:"2.0") {
                title = "My test feed"
                link = "http://localhost:8080/Blog/post/feed"
                description = "The funky Grails news feed"

                Post.list().each() { post ->
                    entry(post.title) {
                        link = "http://localhost:8080/Blog/post/show/${post.id}"
                        post.body // return the content
                    }
                }
            }
        }    


     然后开始添加Comment,你在保存完Post后,应该发现了,Post的show页面里面就有一个Comment的字段来显示Comment。而Comment本来就有add方法,所以只需要两个整合一下就可以了,将Comment的create.gsp页面的form内容copy到Post的show.gsp页面里面去。在g:form标签里面添加一个属性
controller="comment"

     因为这个页面现在有两个form,而此页面默认的controller是PostController,所以修改此controller为Comment。然后修改一下CommentController里的save Action,重定向修改为
redirect(controller:'post',action:'show',id:commentInstance.post.id)

即保存后还跳转到此post的show.gsp页面。页面结构就先不管了,功能是实现了。很简单吧!(我摸索了差不多1天时间

     最后就是添加AJAX了。
     Grails默认装载Prototype 库,但是通过Plug-in 系统提供像Dojo , Yahoo UI 和 Google Web Toolkit 等其他框架的支持.(Grails中文参考手册).
     这里就使用默认支持的Prototype。在Post的show.gsp页面的head标签里面添加,Prototype支持。
<g:javascript library="prototype" />


     最后就是AJAX实现,就是使用一个标签和render就可以了。将页面里面提交comment的按钮修改为AJAX按钮。同时将g:form里面的属性都去掉就可以了。
<div class="buttons">
            <g:submitToRemote controller="comment" action="save" update="[success:'comments',failure:'error']" value="CreateComment"/>
        </div>

这里的update就是动态刷新用的,成功就刷新id为comments的标签,否则就是id为error的标签。
修改下save Action.将rediect修改为render。这里应该是我对Grails不熟悉的原因。由于在gsp里面列Comment的标签是g:each,我不知道是否可以动态的改变它,我没找到办法,或者就是不可以。我直接在ul上加的comments id。然后在save Action里面组装了一下得到的Comments,返回一个str.
def save = {
        def commentInstance = new Comment(params)
        if(!commentInstance.hasErrors() && commentInstance.save()) {
            flash.message = "Comment ${commentInstance.id} created"
            def comments = Comment.findAllByPost(commentInstance.post)
            def str = ""
            comments.each {str = str + "<li>" + it + "</li>"}
            render(str)
//            redirect(controller:'post',action:'show',id:commentInstance.post.id)
        }
        else {
            render(view:'create',model:[commentInstance:commentInstance])
        }
    }

    这样,整个Blog就搞定了。页面上差异肯定是比较大一点,修改就行了。功能和ruby的基本相同了。有一点不同的应该是RSS那里,ruby会在浏览器的地址栏出现一个rss标签,而这里只能输入地址,应该也是可以的,我刚接触而已,做个实验罢了。如果熟悉Grails,相信15分钟之内是能搞定这个的!

ps:附件不知道会不会乱码,linux下打的包。。。。
  • 大小: 46.2 KB
4
1
分享到:
评论
2 楼 winking6gr 2009-12-03  
在编辑状态下,右键代码的任意位置,选择generate,就可以生成controller等文件。
1 楼 ehow 2009-10-15  
挺好,哥们加油

相关推荐

    grails开发指南第二版

    This includes a large number of Java developers who have been enticed by the productivity gains seen with frameworks such as Ruby on Rails, JRuby on Rails, etc. The Web and its environment is a ...

    grails 开发框架-5

    grails1.0开发框架5 类似于ruby on rails的框架。

    grails 开发框架-1

    grails1.0开发框架1 类似于ruby on rails的框架。

    grails 开发框架-3

    grails1.0开发框架3 类似于ruby on rails的框架。

    grails 开发框架-4

    grails1.0开发框架4 类似于ruby on rails的框架。

    Griffon In Action

    Griffon leverages years of experience and lessons learned by Grails, Groovy, Rails, Ruby, Java Desktop, and Java developers and their communities. Griffon has adopted many of those languages’ and ...

    Grails Wed开发课程设计

    Grails构建在开源技术如Spring、Hibernate和SiteMesh之上,提供了一个类似于Rails的平台可以与Java平台无缝集成的。但Grails比Rails具有更强的可像Java那样成熟的虚拟机,并且能够给企业级的服务提供成熟的支持。...

    grails开发框架6

    grails1.0开发框架6 类似于ruby on rails的框架。

    grails 开发框架-2

    grails1.0开发框架2 类似于ruby on rails的框架。

    Dash for Mac 2.0.2 文档查看神器 破解版

    X CodeIgniter CoffeeScript ColdFusion Common Lisp Compass Cordova Corona CSS D3.js Django Dojo Toolkit Drupal Elixir Emacs Lisp Ember....ExtJS Flask Foundation GLib Go Grails Groovy Grunt Haml Haskell ...

    SPRING攻略 第2版.pdf

    你在寻求和Ruby on Rails一样的一体化架构吗?那么你会被Grails等Spring替代方案所深深吸引,对于Groovy开发人员来说,Grails具有难以置信的能力和生产率。如果你是寻求快速、轻量级的应用构建方法的Java开发人员,...

    SPRING攻略 第2版

    你在寻求和Ruby on Rails一样的一体化架构吗?那么你会被Grails等Spring替代方案所深深吸引,对于Groovy开发人员来说,Grails具有难以置信的能力和生产率。如果你是寻求快速、轻量级的应用构建方法的Java开发人员,...

    Spring攻略(第二版)高清版

    你在寻求和Ruby on Rails一样的一体化架构吗?那么你会被Grails等Spring替代方案所深深吸引,对于Groovy开发人员来说,Grails具有难以置信的能力和生产率。如果你是寻求快速、轻量级的应用构建方法的Java开发人员,...

    SPRING攻略 第2版 (带书签)(一)

    你在寻求和Ruby on Rails一样的一体化架构吗?那么你会被Grails等Spring替代方案所深深吸引,对于Groovy开发人员来说,Grails具有难以置信的能力和生产率。如果你是寻求快速、轻量级的应用构建方法的Java开发人员,...

    SPRING攻略 第2版 (带书签)(二)

    你在寻求和Ruby on Rails一样的一体化架构吗?那么你会被Grails等Spring替代方案所深深吸引,对于Groovy开发人员来说,Grails具有难以置信的能力和生产率。如果你是寻求快速、轻量级的应用构建方法的Java开发人员,...

    Spring攻略 英文第二版

    你在寻求和Ruby on Rails一样的一体化架构吗?那么你会被Grails等Spring替代方案所深深吸引,对于Groovy开发人员来说,Grails具有难以置信的能力和生产率。如果你是寻求快速、轻量级的应用构建方法的Java开发人员,...

Global site tag (gtag.js) - Google Analytics