Play框架127版本教程(2) - 數(shù)據(jù)模型的首次迭代_第1頁
Play框架127版本教程(2) - 數(shù)據(jù)模型的首次迭代_第2頁
Play框架127版本教程(2) - 數(shù)據(jù)模型的首次迭代_第3頁
Play框架127版本教程(2) - 數(shù)據(jù)模型的首次迭代_第4頁
Play框架127版本教程(2) - 數(shù)據(jù)模型的首次迭代_第5頁
已閱讀5頁,還剩13頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、數(shù)據(jù)模型的首次迭代接下來我們要開始完成我們的博客引擎的模型部分。JPA入門模型層是一個(gè)Play應(yīng)用的核心(對(duì)于其他Web框架也同樣成立)。它是一個(gè)對(duì)應(yīng)用操作的資源的領(lǐng)域特定的表示。因?yàn)槲覀兿胍獎(jiǎng)?chuàng)建一個(gè)博客引擎,模型層就包括User,Post和Comment(用戶,博文和評(píng)論)。因?yàn)榇蠖鄶?shù)模型對(duì)象需要在應(yīng)用停止運(yùn)行時(shí)保留下來,我們需要把它們存儲(chǔ)在持久性數(shù)據(jù)庫中。一個(gè)普遍的選擇是使用關(guān)系型數(shù)據(jù)庫。因?yàn)镴ava是一個(gè)面向?qū)ο蟮恼Z言,我們將使用一個(gè)ORM來減少一些繁瑣的工作。JPA是一個(gè)給ORM定義一套標(biāo)準(zhǔn)API的Java規(guī)范。作為一個(gè)JPA的實(shí)現(xiàn),Play使用猿媛皆知的Hibernate框架。之所以

2、使用JPA而不是原生的Hibernate API,是因?yàn)檫@樣所有的映射都可以用Java對(duì)象直接完成。如果之前用過Hibernate或JPA,你將驚訝于Play所添加的包裝。不再需要配置什么了;JPA與Play框架合一。如果你不知道JPA,你可以在繼續(xù)之前閱讀一些JPA實(shí)現(xiàn)的介紹User類我們首先來完成User類。創(chuàng)建新文件/yabe/app/models/User.java,并寫入下面的內(nèi)容:package models;import java.util.*;import javax.persistence.*;import play.db.jpa.*;Entitypublic class U

3、ser extends Model public String email; public String password; public String fullname; public boolean isAdmin; public User(String email, String password, String fullname) this.email = email; this.password = password; this.fullname = fullname; Entity注解(annotation)標(biāo)記該類成為托管的JPA實(shí)體(managed JPA Entity),而M

4、odel父類將自動(dòng)提供一些接下來將會(huì)用到的有用的JPA輔助函數(shù)。這個(gè)類的所有成員變量都會(huì)被持久化到數(shù)據(jù)庫中。默認(rèn)情況下,對(duì)應(yīng)的表就是'User'。如果想要使用一個(gè)'user'是保留關(guān)鍵字的數(shù)據(jù)庫,你需要給JPA映射指定一個(gè)不同的表名。要想這么做,使用Table(name="blog_user")注解User類。你的模型對(duì)象不一定得繼承自play.db.jpa.Model類。你也可以使用原生JPA。但繼承自該類往往是個(gè)更好的選擇,因?yàn)樗沟眠\(yùn)用JPA變得更為簡單。如果之前用過JPA,你知道每個(gè)JPA實(shí)體都需要提供一個(gè)Id屬性。在這里,Model

5、父類已經(jīng)提供了一個(gè)自動(dòng)生成的ID,在大多數(shù)情況下,這樣就行了。不要認(rèn)為生成的id成員變量是函數(shù)變量(functional identifier),其實(shí)它是技術(shù)變量(technical identifier)。區(qū)分這兩概念通常是個(gè)好主意,記住自動(dòng)生成的ID是一個(gè)技術(shù)變量(譯注:這里我弄不懂,以下附上原文)Dont think about this provided id field as a functional identifier but as a technical identifier. It is generally a good idea to keep both

6、 concepts separated and to keep an automatically generated numeric ID as a technical identifier.如果你寫過Java,心中可能已經(jīng)敲起了警鐘,因?yàn)槲覀兙尤淮罅渴褂霉谐蓡T!在Java(一如其他面向?qū)ο笳Z言),最佳實(shí)踐通常是盡量保持各成員私有,并提供getter和setter。這就是封裝,面向?qū)ο笤O(shè)計(jì)的基本概念之一。事實(shí)上,Play已經(jīng)考慮到這一點(diǎn),在自動(dòng)生成getter和setter的同時(shí)保持封裝;等下我們將看到它是怎么做到的?,F(xiàn)在你可以刷新主頁面,看一下結(jié)果。當(dāng)然,除非你犯錯(cuò),否則應(yīng)該什么變化都看不

7、到:D。Play自動(dòng)編譯并加載了User類,不過這沒有給應(yīng)用添加任何新特性。寫下第一個(gè)測試測試新增的User類的一個(gè)好方法是寫下JUnit測試用例。它會(huì)允許你增量開發(fā)的同時(shí)保證一切安好。要運(yùn)行一個(gè)測試用例,你需要在'test'模式下運(yùn)行應(yīng)用。停止當(dāng)前正在運(yùn)行的應(yīng)用,打開命令行并輸入:$ play testplay test命令就像play run,不過它加載的是一個(gè)測試運(yùn)行器模塊,使得你可以直接在瀏覽器中運(yùn)行測試套件。當(dāng)你在test mode中運(yùn)行Play應(yīng)用時(shí),Play會(huì)自動(dòng)切換到test框架ID并加載對(duì)應(yīng)的application.conf。閱讀框架ID文檔來了解更多。在瀏覽

8、器打開http:/localhost:9000/tests頁面來看看測試運(yùn)行器。嘗試選擇所有的默認(rèn)測試并運(yùn)行;應(yīng)該全部都會(huì)是綠色但是默認(rèn)的測試其實(shí)什么都沒測:D我們將使用JUnit測試來測試模型部分。如你所見,已經(jīng)存在一個(gè)默認(rèn)的BasicTests.java,所以讓我們打開它(/yabe/test/BasicTest.java):import org.junit.*;import play.test.*;import models.*;public class BasicTest extends UnitTest Test public void aVeryImportantThingToTe

9、st() assertEquals(2, 1 + 1); 刪除沒用的默認(rèn)測試(aVeryImportantThingToTest),創(chuàng)建一個(gè)注冊(cè)新用戶并進(jìn)行檢查的測試:Testpublic void createAndRetrieveUser() / Create a new user and save it new User("bob", "secret", "Bob").save(); / Retrieve the user with e-mail address bob User bob = User.find("by

10、Email", "bob").first(); / Test assertNotNull(bob); assertEquals("Bob", bob.fullname);如你所見,Model父類給我們提供了兩個(gè)非常有用的方法:save()和find()。你可以在Play文檔中的JPA支持閱讀到Model類的更多方法。在test runner中選擇BasicTests.java,點(diǎn)擊開始,看一下是不是全都變綠了。我們將需要在User類中添加一個(gè)方法,來檢查給用戶的用戶名和密碼是否存在了。讓我們完成它,并且測試它。在User.java中,添加con

11、nect()方法:public static User connect(String email, String password) return find("byEmailAndPassword", email, password).first();如今測試用例成這樣:Testpublic void tryConnectAsUser() / Create a new user and save it new User("bob", "secret", "Bob").save(); / Test assertNot

12、Null(User.connect("bob", "secret"); assertNull(User.connect("bob", "badpassword"); assertNull(User.connect("tom", "secret");每次修改之后,你都可以從Play測試運(yùn)行器運(yùn)行所有的測試,來確保沒有什么被破壞了。Post類Post類表示博客文章。讓我們寫下代碼:package models;import java.util.*;import javax.per

13、sistence.*;import play.db.jpa.*;Entitypublic class Post extends Model public String title; public Date postedAt; Lob public String content; ManyToOne public User author; public Post(User author, String title, String content) this.author = author; this.title = title; this.content = content; this.post

14、edAt = new Date(); 這里我們使用Lob注解告訴JPA來使用字符大對(duì)象類型(clob)來存儲(chǔ)文章內(nèi)容。我們也聲明跟User類的關(guān)系是ManyToOne。這意味著每個(gè)Post對(duì)應(yīng)一個(gè)User,而每個(gè)User可以有多個(gè)Post。PostgreSQL的最近版本不會(huì)將Lob注解的String成員存儲(chǔ)成字符大對(duì)象類型,除非你額外用Type(type = "org.hibernate.type.TextType")注解該成員。我們將寫一個(gè)新的測試用例來檢查Post類能否正常工作。但在寫下更多測試之前,我們需要修改下JUnit測試類。在當(dāng)前測試中,數(shù)據(jù)庫的內(nèi)容永不刪除,所

15、以每次運(yùn)行測試都會(huì)創(chuàng)建越來越多的對(duì)象。假如將來我們需要測試對(duì)象的數(shù)目是否正確,這將會(huì)是一個(gè)問題。所以先寫一個(gè)JUnit的setup()方法在每次測試之前清空數(shù)據(jù)庫:public class BasicTest extends UnitTest Before public void setup() Fixtures.deleteDatabase(); Before是JUnit測試工具的一個(gè)核心概念如你所見,F(xiàn)ixtures類是一個(gè)在測試時(shí)幫助處理數(shù)據(jù)庫的類。再次運(yùn)行測試并檢查是否一切安好。之后接著下下一個(gè)測試:Testpublic void createPost() / Create a new

16、 user and save it User bob = new User("bob", "secret", "Bob").save(); / Create a new post new Post(bob, "My first post", "Hello world").save(); / Test that the post has been created assertEquals(1, Post.count(); / Retrieve all posts created by Bob Li

17、st<Post> bobPosts = Post.find("byAuthor", bob).fetch(); / Tests assertEquals(1, bobPosts.size(); Post firstPost = bobPosts.get(0); assertNotNull(firstPost); assertEquals(bob, firstPost.author); assertEquals("My first post", firstPost.title); assertEquals("Hello world&q

18、uot;, firstPost.content); assertNotNull(firstPost.postedAt);不要忘記導(dǎo)入java.util.List,否則你會(huì)得到一個(gè)編譯錯(cuò)誤。添加Comment類最后,我們需要給博文添加評(píng)論功能。創(chuàng)建Comment類的方式十分簡單直白。package models;import java.util.*;import javax.persistence.*;import play.db.jpa.*;Entitypublic class Comment extends Model public String author; public Date po

19、stedAt; Lob public String content; ManyToOne public Post post; public Comment(Post post, String author, String content) this.post = post; this.author = author; this.content = content; this.postedAt = new Date(); 讓我們寫下第一個(gè)測試用例:Testpublic void postComments() / Create a new user and save it User bob = n

20、ew User("bob", "secret", "Bob").save(); / Create a new post Post bobPost = new Post(bob, "My first post", "Hello world").save(); / Post a first comment new Comment(bobPost, "Jeff", "Nice post").save(); new Comment(bobPost, "T

21、om", "I knew that !").save(); / Retrieve all comments List<Comment> bobPostComments = Comment.find("byPost", bobPost).fetch(); / Tests assertEquals(2, bobPostComments.size(); Comment firstComment = bobPostComments.get(0); assertNotNull(firstComment); assertEquals("

22、;Jeff", firstComment.author); assertEquals("Nice post", firstComment.content); assertNotNull(firstComment.postedAt); Comment secondComment = bobPostComments.get(1); assertNotNull(secondComment); assertEquals("Tom", secondComment.author); assertEquals("I knew that !"

23、;, secondComment.content); assertNotNull(secondComment.postedAt);你可以看到Post和Comments之間的聯(lián)系并不緊密:我們不得不通過查詢來獲得所有跟某一個(gè)Post關(guān)聯(lián)的評(píng)論。通過在Post和Comment類之間建立新的關(guān)系,我們可以改善這一點(diǎn)。在Post類添加comments成員:.OneToMany(mappedBy="post", cascade=CascadeType.ALL)public List<Comment> comments;public Post(User author, St

24、ring title, String content) ments = new ArrayList<Comment>(); this.author = author; this.title = title; this.content = content; this.postedAt = new Date();.注意現(xiàn)在我們用mappedBy屬性來告訴JPAComment類的post成員是維持這個(gè)關(guān)系的一方。當(dāng)你用JPA定義一個(gè)雙向關(guān)系時(shí),需要指定哪一方來維持這個(gè)關(guān)系。在這個(gè)例子中,因?yàn)镃omment示例依賴于Post,我們按Comment.post的反向來定義關(guān)系。我們也設(shè)置了ca

25、scade屬性來告訴JPA,我們希望Post的刪除將級(jí)聯(lián)影響到comments。也即是,如果你刪除一個(gè)博文時(shí),所有相關(guān)的評(píng)論也將一并刪除。由于有了這個(gè)新關(guān)系,我們可以給Post類添加一個(gè)輔助方法來簡化評(píng)論的添加:public Post addComment(String author, String content) Comment newComment = new Comment(this, author, content).save(); ments.add(newComment); this.save(); return this;讓我們寫多一個(gè)測試檢查它能否工作:Testpublic

26、void useTheCommentsRelation() / Create a new user and save it User bob = new User("bob", "secret", "Bob").save(); / Create a new post Post bobPost = new Post(bob, "My first post", "Hello world").save(); / Post a first comment bobPost.addComment("

27、;Jeff", "Nice post"); bobPost.addComment("Tom", "I knew that !"); / Count things assertEquals(1, User.count(); assertEquals(1, Post.count(); assertEquals(2, Comment.count(); / Retrieve Bob's post bobPost = Post.find("byAuthor", bob).first(); assertNot

28、Null(bobPost); / Navigate to comments assertEquals(2, bobPments.size(); assertEquals("Jeff", bobPments.get(0).author); / Delete the post bobPost.delete(); / Check that all comments have been deleted assertEquals(1, User.count(); assertEquals(0, Post.count(); assertEquals(0, Comment.count()

29、;這次全綠了么?使用Fixtures來寫更復(fù)雜的測試當(dāng)你開始寫更加復(fù)雜的測試,你通常需要一些測試數(shù)據(jù)。Fixtures允許你在一個(gè)YAML文件中描述你的模型,并在測試開始前加載。編輯/yabe/test/data.yml并開始描述一個(gè)User:User(bob): email: bob password: secret fullname: Bob.呃,因?yàn)閐ata.yml有點(diǎn)大,你可以在這里下載它?,F(xiàn)在我們可以創(chuàng)建一個(gè)加載數(shù)據(jù)并對(duì)它運(yùn)行一些斷言的測試用例:Testpublic void fullTest() Fixtures.loadModels("data.yml");

30、/ Count things assertEquals(2, User.count(); assertEquals(3, Post.count(); assertEquals(3, Comment.count(); / Try to connect as users assertNotNull(User.connect("bob", "secret"); assertNotNull(User.connect("jeff", "secret"); assertNull(User.connect("jeff", "badpassword"); assertNull(User.connect("tom", "secret"); / Find all of Bob's posts List<Post> bobPosts = Post.find("a

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論