博客主頁如今已經完成,接下來要完成博客正文頁面。整個頁面將展現當前文章的全部評論,還包括一個用於提交新的評論的表單。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。