博客主页如今已经完成,接下来要完成博客正文页面。整个页面将展现当前文章的全部评论,还包括一个用于提交新的评论的表单。javascript
要显示文章内容,咱们须要在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是:
/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类构造函数中的每一个参数。有了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来自动聚焦到发生错误的地方。首先,须要JQuery和JQuery 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>
如今评论框看起来真的美极了。咱们还有加多两样东西。
首先,咱们将在评论成功提交以后显示一个成功信息。为此,咱们须要使用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' /} …
最后咱们将修改postComment
action所用的URL。由于咱们没有给它指定路由,如今它用的是默认的路由。因此在应用的路由文件中添加下面一行:
POST /posts/{postId}/comments Application.postComment
终于完成了。记得把改动提交到bazaar。