国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

[翻譯]Play框架1.2.7版本教程(2) - 數(shù)據(jù)模型的首次迭代

charles_paul / 2479人閱讀

摘要:數(shù)據(jù)模型的首次迭代接下來(lái)我們要開始完成我們的博客引擎的模型部分。一個(gè)普遍的選擇是使用關(guān)系型數(shù)據(jù)庫(kù)。不要認(rèn)為生成的成員變量是函數(shù)變量,其實(shí)它是技術(shù)變量。當(dāng)你在中運(yùn)行應(yīng)用時(shí),會(huì)自動(dòng)切換到框架并加載對(duì)應(yīng)的。再次運(yùn)行測(cè)試并檢查是否一切安好。

數(shù)據(jù)模型的首次迭代

接下來(lái)我們要開始完成我們的博客引擎的模型部分。

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í)保留下來(lái),我們需要把它們存儲(chǔ)在持久性數(shù)據(jù)庫(kù)中。一個(gè)普遍的選擇是使用關(guān)系型數(shù)據(jù)庫(kù)。因?yàn)镴ava是一個(gè)面向?qū)ο蟮恼Z(yǔ)言,我們將使用一個(gè)ORM來(lái)減少一些繁瑣的工作。

JPA是一個(gè)給ORM定義一套標(biāo)準(zhǔn)API的Java規(guī)范。作為一個(gè)JPA的實(shí)現(xiàn),Play使用猿媛皆知的Hibernate框架。之所以使用JPA而不是原生的Hibernate API,是因?yàn)檫@樣所有的映射都可以用Java對(duì)象直接完成。

如果之前用過(guò)Hibernate或JPA,你將驚訝于Play所添加的包裝。不再需要配置什么了;JPA與Play框架合一。

如果你不知道JPA,你可以在繼續(xù)之前閱讀一些JPA實(shí)現(xiàn)的介紹

User類

我們首先來(lái)完成User類。創(chuàng)建新文件/yabe/app/models/User.java,并寫入下面的內(nèi)容:

package models;

import java.util.*;
import javax.persistence.*;

import play.db.jpa.*;

@Entity
public class User 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),而Model父類將自動(dòng)提供一些接下來(lái)將會(huì)用到的有用的JPA輔助函數(shù)。這個(gè)類的所有成員變量都會(huì)被持久化到數(shù)據(jù)庫(kù)中。

  

默認(rèn)情況下,對(duì)應(yīng)的表就是"User"。如果想要使用一個(gè)"user"是保留關(guān)鍵字的數(shù)據(jù)庫(kù),你需要給JPA映射指定一個(gè)不同的表名。要想這么做,使用@Table(name="blog_user")注解User類。

  

你的模型對(duì)象不一定得繼承自play.db.jpa.Model類。你也可以使用原生JPA。但繼承自該類往往是個(gè)更好的選擇,因?yàn)樗沟眠\(yùn)用JPA變得更為簡(jiǎn)單。

如果之前用過(guò)JPA,你知道每個(gè)JPA實(shí)體都需要提供一個(gè)@Id屬性。在這里,Model父類已經(jīng)提供了一個(gè)自動(dòng)生成的ID,在大多數(shù)情況下,這樣就行了。

  

不要認(rèn)為生成的id成員變量是函數(shù)變量(functional identifier),其實(shí)它是技術(shù)變量(technical identifier)。區(qū)分這兩概念通常是個(gè)好主意,記住自動(dòng)生成的ID是一個(gè)技術(shù)變量(譯注:這里我弄不懂,以下附上原文)

  

Don’t think about this provided id field as a functional identifier but as a technical identifier. It is generally a good idea to keep both concepts separated and to keep an automatically generated numeric ID as a technical identifier.

如果你寫過(guò)Java,心中可能已經(jīng)敲起了警鐘,因?yàn)槲覀兙尤淮罅渴褂霉谐蓡T!在Java(一如其他面向?qū)ο笳Z(yǔ)言),最佳實(shí)踐通常是盡量保持各成員私有,并提供getter和setter。這就是封裝,面向?qū)ο笤O(shè)計(jì)的基本概念之一。事實(shí)上,Play已經(jīng)考慮到這一點(diǎn),在自動(dòng)生成getter和setter的同時(shí)保持封裝;等下我們將看到它是怎么做到的。

現(xiàn)在你可以刷新主頁(yè)面,看一下結(jié)果。當(dāng)然,除非你犯錯(cuò),否則應(yīng)該什么變化都看不到:D。Play自動(dòng)編譯并加載了User類,不過(guò)這沒有給應(yīng)用添加任何新特性。

寫下第一個(gè)測(cè)試

測(cè)試新增的User類的一個(gè)好方法是寫下JUnit測(cè)試用例。它會(huì)允許你增量開發(fā)的同時(shí)保證一切安好。

要運(yùn)行一個(gè)測(cè)試用例,你需要在"test"模式下運(yùn)行應(yīng)用。停止當(dāng)前正在運(yùn)行的應(yīng)用,打開命令行并輸入:

~$ play test

play test命令就像play run,不過(guò)它加載的是一個(gè)測(cè)試運(yùn)行器模塊,使得你可以直接在瀏覽器中運(yùn)行測(cè)試套件。

  

當(dāng)你在test mode中運(yùn)行Play應(yīng)用時(shí),Play會(huì)自動(dòng)切換到test框架ID并加載對(duì)應(yīng)的application.conf。閱讀框架ID文檔來(lái)了解更多。

在瀏覽器打開http://localhost:9000/@tests頁(yè)面來(lái)看看測(cè)試運(yùn)行器。嘗試選擇所有的默認(rèn)測(cè)試并運(yùn)行;應(yīng)該全部都會(huì)是綠色……但是默認(rèn)的測(cè)試其實(shí)什么都沒測(cè):D

我們將使用JUnit測(cè)試來(lái)測(cè)試模型部分。如你所見,已經(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 aVeryImportantThingToTest() {
        assertEquals(2, 1 + 1);
    }

}

刪除沒用的默認(rèn)測(cè)試(aVeryImportantThingToTest),創(chuàng)建一個(gè)注冊(cè)新用戶并進(jìn)行檢查的測(cè)試:

@Test
public void createAndRetrieveUser() {
    // Create a new user and save it
    new User("bob@gmail.com", "secret", "Bob").save();

    // Retrieve the user with e-mail address bob@gmail.com
    User bob = User.find("byEmail", "bob@gmail.com").first();

    // Test 
    assertNotNull(bob);
    assertEquals("Bob", bob.fullname);
}

如你所見,Model父類給我們提供了兩個(gè)非常有用的方法:save()find()

  

你可以在Play文檔中的JPA支持閱讀到Model類的更多方法。

在test runner中選擇BasicTests.java,點(diǎn)擊開始,看一下是不是全都變綠了。

我們將需要在User類中添加一個(gè)方法,來(lái)檢查給用戶的用戶名和密碼是否存在了。讓我們完成它,并且測(cè)試它。

User.java中,添加connect()方法:

public static User connect(String email, String password) {
    return find("byEmailAndPassword", email, password).first();
}

如今測(cè)試用例成這樣:

@Test
public void tryConnectAsUser() {
    // Create a new user and save it
    new User("bob@gmail.com", "secret", "Bob").save();

    // Test 
    assertNotNull(User.connect("bob@gmail.com", "secret"));
    assertNull(User.connect("bob@gmail.com", "badpassword"));
    assertNull(User.connect("tom@gmail.com", "secret"));
}

每次修改之后,你都可以從Play測(cè)試運(yùn)行器運(yùn)行所有的測(cè)試,來(lái)確保沒有什么被破壞了。

Post類

Post類表示博客文章。讓我們寫下代碼:

package models;

import java.util.*;
import javax.persistence.*;

import play.db.jpa.*;

@Entity
public 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.postedAt = new Date();
    }

}

這里我們使用@Lob注解告訴JPA來(lái)使用字符大對(duì)象類型(clob)來(lái)存儲(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è)新的測(cè)試用例來(lái)檢查Post類能否正常工作。但在寫下更多測(cè)試之前,我們需要修改下JUnit測(cè)試類。在當(dāng)前測(cè)試中,數(shù)據(jù)庫(kù)的內(nèi)容永不刪除,所以每次運(yùn)行測(cè)試都會(huì)創(chuàng)建越來(lái)越多的對(duì)象。假如將來(lái)我們需要測(cè)試對(duì)象的數(shù)目是否正確,這將會(huì)是一個(gè)問(wèn)題。

所以先寫一個(gè)JUnit的setup()方法在每次測(cè)試之前清空數(shù)據(jù)庫(kù):

public class BasicTest extends UnitTest {

    @Before
    public void setup() {
        Fixtures.deleteDatabase();
    }

    …
}
  

@Before是JUnit測(cè)試工具的一個(gè)核心概念

如你所見,Fixtures類是一個(gè)在測(cè)試時(shí)幫助處理數(shù)據(jù)庫(kù)的類。再次運(yùn)行測(cè)試并檢查是否一切安好。之后接著下下一個(gè)測(cè)試:

@Test
public void createPost() {
    // Create a new user and save it
    User bob = new User("bob@gmail.com", "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
    List 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", firstPost.content);
    assertNotNull(firstPost.postedAt);
}
  

不要忘記導(dǎo)入java.util.List,否則你會(huì)得到一個(gè)編譯錯(cuò)誤。

添加Comment類

最后,我們需要給博文添加評(píng)論功能。

創(chuàng)建Comment類的方式十分簡(jiǎn)單直白。

package models;

import java.util.*;
import javax.persistence.*;

import play.db.jpa.*;

@Entity
public class Comment extends Model {

    public String author;
    public Date postedAt;

    @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è)測(cè)試用例:

@Test
public void postComments() {
    // Create a new user and save it
    User bob = new User("bob@gmail.com", "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, "Tom", "I knew that !").save();

    // Retrieve all comments
    List bobPostComments = Comment.find("byPost", bobPost).fetch();

    // Tests
    assertEquals(2, bobPostComments.size());

    Comment firstComment = bobPostComments.get(0);
    assertNotNull(firstComment);
    assertEquals("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 !", secondComment.content);
    assertNotNull(secondComment.postedAt);
}

你可以看到PostComments之間的聯(lián)系并不緊密:我們不得不通過(guò)查詢來(lái)獲得所有跟某一個(gè)Post關(guān)聯(lián)的評(píng)論。通過(guò)在PostComment類之間建立新的關(guān)系,我們可以改善這一點(diǎn)。

Post類添加comments成員:

...
@OneToMany(mappedBy="post", cascade=CascadeType.ALL)
public List comments;

public Post(User author, String title, String content) { 
    this.comments = new ArrayList();
    this.author = author;
    this.title = title;
    this.content = content;
    this.postedAt = new Date();
}
...

注意現(xiàn)在我們用mappedBy屬性來(lái)告訴JPAComment類的post成員是維持這個(gè)關(guān)系的一方。當(dāng)你用JPA定義一個(gè)雙向關(guān)系時(shí),需要指定哪一方來(lái)維持這個(gè)關(guān)系。在這個(gè)例子中,因?yàn)?b>Comment示例依賴于Post,我們按Comment.post的反向來(lái)定義關(guān)系。

我們也設(shè)置了cascade屬性來(lái)告訴JPA,我們希望Post的刪除將級(jí)聯(lián)影響到comments。也即是,如果你刪除一個(gè)博文時(shí),所有相關(guān)的評(píng)論也將一并刪除。

由于有了這個(gè)新關(guān)系,我們可以給Post類添加一個(gè)輔助方法來(lái)簡(jiǎn)化評(píng)論的添加:

public Post addComment(String author, String content) {
    Comment newComment = new Comment(this, author, content).save();
    this.comments.add(newComment);
    this.save();
    return this;
}

讓我們寫多一個(gè)測(cè)試檢查它能否工作:

@Test
public void useTheCommentsRelation() {
    // Create a new user and save it
    User bob = new User("bob@gmail.com", "secret", "Bob").save();

    // Create a new post
    Post bobPost = new Post(bob, "My first post", "Hello world").save();

    // Post a first comment
    bobPost.addComment("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();
    assertNotNull(bobPost);

    // Navigate to comments
    assertEquals(2, bobPost.comments.size());
    assertEquals("Jeff", bobPost.comments.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());
}

這次全綠了么?

使用Fixtures來(lái)寫更復(fù)雜的測(cè)試

當(dāng)你開始寫更加復(fù)雜的測(cè)試,你通常需要一些測(cè)試數(shù)據(jù)。Fixtures允許你在一個(gè)YAML文件中描述你的模型,并在測(cè)試開始前加載。

編輯/yabe/test/data.yml并開始描述一個(gè)User:

User(bob):
    email: bob@gmail.com
    password: secret
    fullname: Bob

...

呃,因?yàn)?b>data.yml有點(diǎn)大,你可以在這里下載它。

現(xiàn)在我們可以創(chuàng)建一個(gè)加載數(shù)據(jù)并對(duì)它運(yùn)行一些斷言的測(cè)試用例:

@Test
public void fullTest() {
    Fixtures.loadModels("data.yml");

    // Count things
    assertEquals(2, User.count());
    assertEquals(3, Post.count());
    assertEquals(3, Comment.count());

    // Try to connect as users
    assertNotNull(User.connect("bob@gmail.com", "secret"));
    assertNotNull(User.connect("jeff@gmail.com", "secret"));
    assertNull(User.connect("jeff@gmail.com", "badpassword"));
    assertNull(User.connect("tom@gmail.com", "secret"));

    // Find all of Bob"s posts
    List bobPosts = Post.find("author.email", "bob@gmail.com").fetch();
    assertEquals(2, bobPosts.size());

    // Find all comments related to Bob"s posts
    List bobComments = Comment.find("post.author.email", "bob@gmail.com").fetch();
    assertEquals(3, bobComments.size());

    // Find the most recent post
    Post frontPost = Post.find("order by postedAt desc").first();
    assertNotNull(frontPost);
    assertEquals("About the model layer", frontPost.title);

    // Check that this post has two comments
    assertEquals(2, frontPost.comments.size());

    // Post a new comment
    frontPost.addComment("Jim", "Hello guys");
    assertEquals(3, frontPost.comments.size());
    assertEquals(4, Comment.count());
}

你可以在YAML manual page中閱讀更多關(guān)于Play和YAML的內(nèi)容。

保存你的成果

現(xiàn)在我們已經(jīng)完成了博客引擎的大部分模型層。既然已經(jīng)創(chuàng)建并測(cè)試好了模型層,我們可以開始開發(fā)這個(gè)Web應(yīng)用了。

不過(guò)在繼續(xù)前進(jìn)之前,是時(shí)候用Bazaar保存你的成果。打開命令行,輸入bzr st來(lái)看看在前一個(gè)提交之后做的修改:

$ bzr st

如你所見,一些新文件不在版本控制之中。test-result目錄不需要加入到版本控制,所以就忽略它。

$ bzr ignore test-result

通過(guò)bzr add向版本控制加入其他文件。

$ bzr add

你現(xiàn)在可以提交你的改動(dòng)了。

$ bzr commit -m "The model layer is ready"

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/64103.html

相關(guān)文章

  • [翻譯]Play框架1.2.7版本教程(11) - 部署應(yīng)用

    摘要:對(duì)的詳細(xì)配置已經(jīng)超出了本教程的范圍,但大體上看上去像這樣然后在中加入下面一行,讓本地的反向代理能夠連接上你的應(yīng)用這才只是個(gè)開始如果一路上你一直跟著本教程,你應(yīng)該已經(jīng)懂得如何開發(fā)一個(gè)應(yīng)用了。 部署應(yīng)用 如今我們已經(jīng)完成了博客引擎了。讓我們來(lái)看一下一些部署Play應(yīng)用的步驟。 定義一個(gè)框架ID 一般,你需要部署你的應(yīng)用到一臺(tái)跟開發(fā)時(shí)不一樣的電腦。這臺(tái)電腦(很有可能是臺(tái)服務(wù)器)上面的P...

    Binguner 評(píng)論0 收藏0
  • [翻譯]Play框架1.2.7版本教程(7) - 通過(guò)CRUD來(lái)實(shí)現(xiàn)一個(gè)基本的管理面板

    摘要:通過(guò)來(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)于本地化信息的更多東西。 通過(guò)CRUD來(lái)實(shí)現(xiàn)一個(gè)基本的管理面板 目前,我們還沒法使用博客的UI來(lái)寫新的文章,或修改評(píng)論。Play提供了一個(gè)即開即用的CRUD模塊,可以快速...

    騫諱護(hù) 評(píng)論0 收藏0
  • [翻譯]Play框架1.2.7版本教程(12) - 國(guó)際化和本地化

    摘要:國(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ǔ)言的支持...

    hoohack 評(píng)論0 收藏0
  • [翻譯]Play框架1.2.7版本教程(1)

    摘要:確保你的文本編輯器已經(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è)教程,是因...

    solocoder 評(píng)論0 收藏0
  • [翻譯]Play框架1.2.7版本教程(10) - 完成應(yīng)用測(cè)試

    摘要:完成應(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)建的博客引擎。不過(guò)這個(gè)項(xiàng)目尚未完全結(jié)束。為了保證代碼的質(zhì)量,我們需要添加更多的測(cè)試。 當(dāng)然我們已經(jīng)完成了測(cè)試所有模型層的功能。所以博客引擎的核心功能已經(jīng)被...

    _Dreams 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<