[翻译]Play框架1.2.7版本教程(4) - 浏览和提交评论

浏览和提交评论

博客主页如今已经完成,接下来要完成博客正文页面。整个页面将展现当前文章的全部评论,还包括一个用于提交新的评论的表单。javascript

建立'show' action

要显示文章内容,咱们须要在Application控制器添加新的action。就叫它show()html

public static void show(Long id) {
    Post post = Post.findById(id);
    render(post);
}

如你所见,整个action简明扼要。咱们接受一个id参数做为Long类型Java对象。而这个参数能够来自于URL路径或HTTP请求正文。java

若是接收到的id参数不是有效的数字,id的值会是null,而Play会在errors容器中新增一个验证错误。jquery

这个action会显示/yabe/app/views/Application/show.html模板:segmentfault

#{extends 'main.html' /}
#{set title:post.title /}

#{display post:post, as:'full' /}

由于以前写好了display标签,写这个页面就变得简单。api

给正文页面添加连接

在display标签中,咱们让全部的连接保持为空(使用#)。是时候让这些连接指向Application.show action。在Play模板中,你能够简单地用@{...}记号来建立连接。这个语法使用路由来“转换”URL成对应的action。浏览器

修改/yabe/app/views/tags/display.html标签:app

…
<h2 class="post-title">
    <a href="@{Application.show(_post.id)}">${_post.title}</a>
</h2>
…

如今刷新主页,点击一个标题来展现正文。函数

呃……好像缺了个返回主页面的连接。修改/yabe/app/views/main.html模板来完成标题连接:post

…
<div id="title">
    <span class="about">About this blog</span>
    <h1><a href="@{Application.index()}">${blogTitle}</a></h1>
    <h2>${blogBaseline}</h2>
</div>
…

如今终于能够在主页和正文之间切换了。

指定一个更语义化的URL

如你所见,正文页面的URL是:

/application/show?id=1

这是由于Play的默认路由规则就是这样:

*       /{controller}/{action}                  {controller}.{action}

经过指定Application.show action的路径,咱们可使用更语义化的URL。修改/yabe/conf/routes并在第一个路由下面添加新的路由:

GET     /posts/{id}                             Application.show

这里id参数将从URL路径提取。你能够从Route File Syntax中阅读更多关于URI模式的内容。

刷新浏览器,检查此次是否使用了正确的URL。

添加分页

要容许用户在文章间方便地流连忘返,咱们须要添加分页机制。咱们将拓展Post类来按需获取上一篇和下一篇文章:

public Post previous() {
    return Post.find("postedAt < ? order by postedAt desc", postedAt).first();
}

public Post next() {
    return Post.find("postedAt > ? order by postedAt asc", postedAt).first();
}

这个方法在每次请求时都会被屡次调用,因此能够优化它们,不过如今先搁置。同时,在show.html模板顶部(在#{display/}标签前)添加分页连接:

<ul id="pagination">
    #{if post.previous()}
        <li id="previous">
            <a href="@{Application.show(post.previous().id)}">
                ${post.previous().title}
            </a>
        </li>
    #{/if}
    #{if post.next()}
        <li id="next">
            <a href="@{Application.show(post.next().id)}">
                ${post.next().title}
            </a>
        </li>
    #{/if}
</ul>

如今是否是更棒了?

添加评论表单

是时候开始完成评论表单。先从在Application控制器中增长postComment action方法开始。

public static void postComment(Long postId, String author, String content) {
    Post post = Post.findById(postId);
    post.addComment(author, content);
    show(postId);
}

如你所见,咱们只是重用了以前添加给Post类的addComment()

show.html模板添加HTML表单(在#{display /}后面):

<h3>Post a comment</h3>

#{form @Application.postComment(post.id)}
    <p>
        <label for="author">Your name: </label>
        <input type="text" name="author" id="author" />
    </p>
    <p>
        <label for="content">Your message: </label>
        <textarea name="content" id="content"></textarea>
    </p>
    <p>
        <input type="submit" value="Submit your comment" />
    </p>
#{/form}

试下提交新的评论。它应该能工做。

comment

添加验证

目前咱们没有在建立评论以前验证表单内容。咱们须要验证表单中包括Comment类构造函数中的每一个参数。有了Play的验证机制,添加验证只是小菜一碟。修改postComment action来加入@Required验证注解,并检查有没有错误产生:

public static void postComment(Long postId, @Required String author, @Required String content) {
    Post post = Post.findById(postId);
    if (validation.hasErrors()) {
        render("Application/show.html", post);
    }
    post.addComment(author, content);
    show(postId);
}

也不要忘了引入play.data/validation.*

如你所见,若是发生验证错误,咱们从新输出正文页面。咱们须要修改表单代码来显示错误信息:

<h3>Post a comment</h3>

#{form @Application.postComment(post.id)}

    #{ifErrors}
        <p class="error">
            All fields are required!
        </p>
    #{/ifErrors}

    <p>
        <label for="author">Your name: </label>
        <input type="text" name="author" id="author" value="${params.author}" />
    </p>
    <p>
        <label for="content">Your message: </label>
        <textarea name="content" id="content">${params.content}</textarea>
    </p>
    <p>
        <input type="submit" value="Submit your comment" />
    </p>
#{/form}

注意到咱们重用已经提交的参数来填充HTML input元素的值。

为了让博客的用户体验更优,咱们将添加一点Javascript来自动聚焦到发生错误的地方。首先,须要JQueryJQuery Tools Expose,你得把它们引入进来。下载这两个库到yabe/public/javascripts/文件夹,并修改main.html模板来引入它们:

…
    <script src="@{'/public/javascripts/jquery-1.4.2.min.js'}"></script>
    <script src="@{'/public/javascripts/jquery.tools-1.2.5.toolbox.expose.min.js'}"></script>
</head>

注意当前版本的Play内置的JQuery要比教程用到的新。

如今你能够在show.html模板底部添加这段代码:

<script type="text/javascript" charset="utf-8">
    $(function() {         
        // Expose the form 
        $('form').click(function() { 
            $('form').expose({api: true}).load(); 
        }); 

        // If there is an error, focus to form
        if($('form .error').size()) {
            $('form').expose({api: true, loadSpeed: 0}).load(); 
            $('form input[type=text]').get(0).focus();
        }
    });
</script>

pretty page

如今评论框看起来真的美极了。咱们还有加多两样东西。

首先,咱们将在评论成功提交以后显示一个成功信息。为此,咱们须要使用flash做用域来容许咱们从一个action调用传递信息到下一个action。

修改postComment来添加成功信息:

public static void postComment(Long postId, @Required String author, @Required String content) {
    Post post = Post.findById(postId);
    if(validation.hasErrors()) {
        render("Application/show.html", post);
    }
    post.addComment(author, content);
    flash.success("Thanks for posting %s", author);
    show(postId);
}

并在show.html顶部添加可能显示成功信息的位置:

…
#{if flash.success}
    <p class="success">${flash.success}</p>
#{/if}

#{display post:post, as:'full' /}
…

finish post page

最后咱们将修改postComment action所用的URL。由于咱们没有给它指定路由,如今它用的是默认的路由。因此在应用的路由文件中添加下面一行:

POST    /posts/{postId}/comments                Application.postComment

终于完成了。记得把改动提交到bazaar。

相关文章
相关标签/搜索