摘要:對(duì)添加標(biāo)簽的支持隨著博客的文章越來(lái)越多,找到要找的文章越來(lái)越難。如果能夠添加標(biāo)簽,那就能更好地分類文章了。要在模式下啟動(dòng)應(yīng)用,輸入添加新的到類確保它能工作。為了保持高效,我們需要向初始數(shù)據(jù)集添加標(biāo)簽測(cè)試數(shù)據(jù)。修改來(lái)添加一些標(biāo)簽數(shù)據(jù)。
對(duì)添加標(biāo)簽的支持
隨著博客的文章越來(lái)越多,找到要找的文章越來(lái)越難。如果能夠添加標(biāo)簽,那就能更好地分類文章了。
Tag模型我們將給博客的模型們添加新成員。對(duì)Tag類的定義是非常簡(jiǎn)單的:
package models; import java.util.*; import javax.persistence.*; import play.db.jpa.*; @Entity public class Tag extends Model implements Comparable{ public String name; private Tag(String name) { this.name = name; } public String toString() { return name; } public int compareTo(Tag otherTag) { return name.compareTo(otherTag.name); } }
因?yàn)橛袝r(shí)想要在需要時(shí)才創(chuàng)建標(biāo)簽,我們寫多一個(gè)findOrCreateByName(String name)工廠方法。把它加到Tag類:
public static Tag findOrCreateByName(String name) { Tag tag = Tag.find("byName", name).first(); if(tag == null) { tag = new Tag(name); } return tag; }給文章打標(biāo)簽
現(xiàn)在是時(shí)候連接Tag和Post模型。讓我們給Post類添加相應(yīng)的關(guān)系:
… @ManyToMany(cascade=CascadeType.PERSIST) public Settags; public Post(User author, String title, String content) { this.comments = new ArrayList (); this.tags = new TreeSet (); this.author = author; this.title = title; this.content = content; this.postedAt = new Date(); } …
注意我們這里使用TreeSet來(lái)保持一個(gè)有序的標(biāo)簽列表。(由于我們之前的compareTo實(shí)現(xiàn),按的是字母順序)
我們將保持該關(guān)系為單向關(guān)系。
我們將給Post類添加一系列輔助函數(shù)。第一個(gè)用于給Post打標(biāo)簽:
… public Post tagItWith(String name) { tags.add(Tag.findOrCreateByName(name)); return this; } …
下一個(gè)是根據(jù)指定標(biāo)簽查找所有文章:
… public static ListfindTaggedWith(String tag) { return Post.find( "select distinct p from Post p join p.tags as t where t.name = ?", tag ).fetch(); } …
是時(shí)候?qū)懸粋€(gè)新的測(cè)試用例了。要在test模式下啟動(dòng)應(yīng)用,輸入:
$ play test
添加新的@Test到BasicTest類:
@Test public void testTags() { // Create a new user and save it User bob = new User("[email protected]", "secret", "Bob").save(); // Create a new post Post bobPost = new Post(bob, "My first post", "Hello world").save(); Post anotherBobPost = new Post(bob, "Hop", "Hello world").save(); // Well assertEquals(0, Post.findTaggedWith("Red").size()); // Tag it now bobPost.tagItWith("Red").tagItWith("Blue").save(); anotherBobPost.tagItWith("Red").tagItWith("Green").save(); // Check assertEquals(2, Post.findTaggedWith("Red").size()); assertEquals(1, Post.findTaggedWith("Blue").size()); assertEquals(1, Post.findTaggedWith("Green").size()); }
確保它能工作。
解決難題如果你想要根據(jù)多個(gè)標(biāo)簽來(lái)查找相應(yīng)的文章,該怎么辦?這個(gè)問題比表面看上去要難。
我將直接給你所需的JPQL查詢語(yǔ)句:
… public static ListfindTaggedWith(String... tags) { return Post.find( "select distinct p from Post p join p.tags as t where t.name in (:tags) group by p.id, p.author, p.title, p.content,p.postedAt having count(t.id) = :size" ).bind("tags", tags).bind("size", tags.length).fetch(); } …
代碼的關(guān)鍵在于,我們需要使用一個(gè)having count語(yǔ)句來(lái)從連結(jié)產(chǎn)生的視圖中過濾出擁有全部標(biāo)簽的文章。
注意這里我們不能用Post.find("...", tags, tags.count)語(yǔ)法,因?yàn)?b>tags是一個(gè)變長(zhǎng)參數(shù)。
你可以在前一個(gè)測(cè)試中加入更多的檢查來(lái)測(cè)試它:
… assertEquals(1, Post.findTaggedWith("Red", "Blue").size()); assertEquals(1, Post.findTaggedWith("Red", "Green").size()); assertEquals(0, Post.findTaggedWith("Red", "Green", "Blue").size()); assertEquals(0, Post.findTaggedWith("Green", "Blue").size()); …標(biāo)簽集合
我們最好有一個(gè)標(biāo)簽集合來(lái)看看有哪些標(biāo)簽。讓我們給Tag類添加一個(gè)方法來(lái)生成標(biāo)簽集合:
public static List
這里,我們使用Hibernate的一個(gè)允許我們從JPA查詢中返回自定義對(duì)象的特性。返回的結(jié)果是一個(gè)Map列表,其中每個(gè)Map包括標(biāo)簽名(鍵)和標(biāo)簽個(gè)數(shù)(值)。
在我們前面的測(cè)試中加多一個(gè)檢查:
… List向博客界面添加標(biāo)簽cloud = Tag.getCloud(); assertEquals( "[{tag=Blue, pound=1}, {tag=Green, pound=1}, {tag=Red, pound=2}]", cloud.toString() );
現(xiàn)在我們又多了一個(gè)瀏覽文章的方式了。為了保持高效,我們需要向初始數(shù)據(jù)集添加標(biāo)簽測(cè)試數(shù)據(jù)。
修改/yabe/conf/initial-data.yml來(lái)添加一些標(biāo)簽數(shù)據(jù)。比如:
… Tag(play): name: Play Tag(architecture): name: Architecture Tag(test): name: Test Tag(mvc): name: MVC …
然后添加它們到文章的聲明中:
… Post(jeffPost): title: The MVC application postedAt: 2009-06-06 author: jeff tags: - play - architecture - mvc content: > A Play …
在YAML文件的頂部添加Tags的定義,因?yàn)樗鼈儠?huì)被Post用到。
你需要重啟應(yīng)用來(lái)加載新的初始數(shù)據(jù)。注意Play甚至?xí)嬖V你出現(xiàn)在YAML文件中的問題:
然后修改#{display /}標(biāo)簽,在全文模式下展示標(biāo)簽集合。修改/yabe/app/views/tags/display.html:
… #{if _as != "full"} | ${_post.comments.size() ?: "no"} comment${_post.comments.size().pluralize()} #{if _post.comments} , latest by ${_post.comments[0].author} #{/if} #{/if} #{elseif _post.tags} - Tagged #{list items:_post.tags, as:"tag"} ${tag}${tag_isLast ? "" : ", "} #{/list} #{/elseif} …標(biāo)簽頁(yè)面
現(xiàn)在我們可以實(shí)現(xiàn)通過標(biāo)簽瀏覽文章了。在#{display /}標(biāo)簽,之前,我們留下一個(gè)空鏈接;現(xiàn)在終于可以用listTagged action補(bǔ)完它(修改yabe/app/views/tags/display.html):
… - Tagged #{list items:post.tags, as:"tag"} ${tag}${tag_isLast ? "" : ", "} #{/list} …
在Application控制器創(chuàng)建action方法:
… public static void listTagged(String tag) { Listposts = Post.findTaggedWith(tag); render(tag, posts); } …
如常,我們創(chuàng)建一個(gè)特定的路由來(lái)保持URI語(yǔ)義化:
GET /posts/{tag} Application.listTagged
我們遇到一個(gè)問題,因?yàn)檫@個(gè)路由跟之前的沖突了。這兩個(gè)路由將匹配同一個(gè)URI:
GET /posts/{id} Application.show GET /posts/{tag} Application.listTagged
不過,因?yàn)槲覀兗僭O(shè)一個(gè)id是數(shù)值類型,而tag不是,我們可以簡(jiǎn)單粗暴地用正則表達(dá)式解決問題:
GET /posts/{<[0-9]+>id} Application.show GET /posts/{tag} Application.listTagged
最后,我們需要?jiǎng)?chuàng)建/yabe/app/views/Application/listTagged.html模板,用于新的listTagged action:
#{extends "main.html" /} #{set title:"Posts tagged with " + tag /} *{********* Title ********* }* #{if posts.size() > 1}There are ${posts.size()} posts tagged "${tag}"
#{/if} #{elseif posts}There is 1 post tagged "${tag}"
#{/elseif} #{else}No post tagged "${tag}"
#{/else} *{********* Posts list *********}*#{list items:posts, as:"post"} #{display post:post, as:"teaser" /} #{/list}
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/64099.html
摘要:通過來(lái)實(shí)現(xiàn)一個(gè)基本的管理面板目前,我們還沒法使用博客的來(lái)寫新的文章,或修改評(píng)論。提供了一個(gè)即開即用的模塊,可以快速生成一個(gè)基本的管理面板。這是因?yàn)槟J(rèn)是以的輸出來(lái)得到一個(gè)模型對(duì)象的表示。在本教程的最后一章,你會(huì)學(xué)到關(guān)于本地化信息的更多東西。 通過CRUD來(lái)實(shí)現(xiàn)一個(gè)基本的管理面板 目前,我們還沒法使用博客的UI來(lái)寫新的文章,或修改評(píng)論。Play提供了一個(gè)即開即用的CRUD模塊,可以快速...
摘要:國(guó)際化和本地化完成了博客引擎后,我們來(lái)考慮額外的一件事應(yīng)用的國(guó)際化和語(yǔ)言的本地化。國(guó)際化和本地化我們將分兩步討論,先是國(guó)際化,再是本地化。實(shí)際上,兩者是同步進(jìn)行的你在國(guó)際化的同時(shí),往往也是在本地化。 國(guó)際化和本地化 完成了博客引擎后,我們來(lái)考慮額外的一件事:Web應(yīng)用的國(guó)際化和語(yǔ)言的本地化。雖然我們可以一開始就做這件事,但是最好還是先完成該應(yīng)用的單一語(yǔ)言版本,然后再添加其他語(yǔ)言的支持...
摘要:完成應(yīng)用測(cè)試我們已經(jīng)完成了我們想要?jiǎng)?chuàng)建的博客引擎。當(dāng)然我們已經(jīng)完成了測(cè)試所有模型層的功能。評(píng)估代碼覆蓋率當(dāng)然我們還沒有完成應(yīng)用所需的所有測(cè)試用例。如你所見,我們遠(yuǎn)遠(yuǎn)沒有完成對(duì)應(yīng)用的全面測(cè)試。 完成應(yīng)用測(cè)試 我們已經(jīng)完成了我們想要?jiǎng)?chuàng)建的博客引擎。不過這個(gè)項(xiàng)目尚未完全結(jié)束。為了保證代碼的質(zhì)量,我們需要添加更多的測(cè)試。 當(dāng)然我們已經(jīng)完成了測(cè)試所有模型層的功能。所以博客引擎的核心功能已經(jīng)被...
摘要:確保你的文本編輯器已經(jīng)做了相應(yīng)的配置。第一個(gè),會(huì)自動(dòng)監(jiān)測(cè)源代碼的改變并在運(yùn)行時(shí)自動(dòng)重載。檢查下面的一行是否出現(xiàn)在應(yīng)用日志中使用版本控制系統(tǒng)來(lái)追蹤變化當(dāng)你開發(fā)一個(gè)項(xiàng)目時(shí),最好使用版本控制系統(tǒng)來(lái)存儲(chǔ)你的源代碼。 Play是一個(gè)Java Web敏捷開發(fā)的框架http://www.playframework.com/documentation/1.2.7/home 之所以要翻譯這個(gè)教程,是因...
摘要:瀏覽和提交評(píng)論博客主頁(yè)現(xiàn)在已經(jīng)完成,接下來(lái)要完成博客正文頁(yè)面。整個(gè)頁(yè)面將展示當(dāng)前文章的所有評(píng)論,還包括一個(gè)用于提交新的評(píng)論的表單。刷新瀏覽器,檢查這次是否使用了正確的。給模板添加表單在后面試下提交新的評(píng)論。 瀏覽和提交評(píng)論 博客主頁(yè)現(xiàn)在已經(jīng)完成,接下來(lái)要完成博客正文頁(yè)面。整個(gè)頁(yè)面將展示當(dāng)前文章的所有評(píng)論,還包括一個(gè)用于提交新的評(píng)論的表單。 創(chuàng)建show action 要顯示文章內(nèi)...
閱讀 3354·2023-04-25 16:25
閱讀 3902·2021-11-15 18:01
閱讀 1642·2021-09-10 11:21
閱讀 3073·2021-08-02 16:53
閱讀 3114·2019-08-30 15:55
閱讀 2514·2019-08-29 16:24
閱讀 2128·2019-08-29 13:14
閱讀 1071·2019-08-29 13:00