Play框架7版本教程-数据模型的首次迭代要点_第1页
Play框架7版本教程-数据模型的首次迭代要点_第2页
Play框架7版本教程-数据模型的首次迭代要点_第3页
Play框架7版本教程-数据模型的首次迭代要点_第4页
Play框架7版本教程-数据模型的首次迭代要点_第5页
免费预览已结束,剩余21页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、数据模型的首次迭代接下来我们要开始完成我们的博客引擎的模型部分。JPA入门模型层是一个Play应用的核心(对于其他Web框架也同样成立)。它是一个对应用操作的 资源的领域特定的表示。因为我们想要创建一个博客引擎,模型层就包括User,Post和Comme nt (用户,博文和评论)。因为大多数模型对象需要在应用停止运行时保留下来,我们需要把它们存储在持久性数据库中。一个普遍的选择是使用关系型数据库。因为Java是一个面向对象的语言,我们将使用一个ORM来减少一些繁琐的工作。JPA是一个给ORM定义一套标准 API的Java规范。作为一个 JPA的实现,Play使用猿 媛皆知的Hibernate

2、框架。之所以使用 JPA而不是原生的 Hibernate API ,是因为这样所有 的映射都可以用 Java对象直接完成。如果之前用过 Hibernate或JPA,你将惊讶于 Play所添加的包装。不再需要配置什么了; JPA与Play框架合一。如果你不知道JPA,你可以在继续之前阅读一些JPA实现的介绍User 类我们首先来完成 User类。创建新文件/yabe/app/models/User.java,并写入下面的内容:package models;import java.util.*;import javax.persistenee.*;import play.db.jpa.*;En t

3、itypublic class User extendsModel public Stri ng email;public String password;public String full name;publicboolea n isAdmi n;public User (Stri ng email, String password, String full name) this .email = email;this.password=password;this.full name =full name;En tity 注解(anno tation )标记该类成为托管的 JPA实体(ma

4、n aged JPA En tity ),而 Model父类将自动提供一些接下来将会用到的有用的JPA辅助函数。这个类的所有成员变量都会被持久化到数据库中。默认情况下,对应的表就是User。如果想要使用一个user是保留关键字的数据库,你需要 给JPA映射指定一个不同的表名。要想这么做,使用Table(name=blog_user) 注解User类。你的模型对象不一定得继承自 play.db.jpa.Model类。你也可以使用原生JPA。但继承自该类往往是个更好的选择,因为它使得运用JPA变得更为简单。如果之前用过JPA,你知道每个JPA实体都需要提供一个 ld属性。在这里,Model父类 已

5、经提供了一个自动生成的ID,在大多数情况下,这样就行了。不要认为生成的id成员变量是函数变量 (functional identifier ),其实它是技术变量(technical identifier )。区分这两概念通常是个好主意,记住自动生成的ID是一个技术变量(译注:这里我弄不懂,以下附上原文)Don t think about this provided id field as a functional identifier but as a technical identifier.It is gen erally a good idea to keep both con cept

6、s separated and to keep an automatically gen erated nu meric ID as a tech ni cal ide ntifier.如果你写过Java ,心中可能已经敲起了警钟,因为我们居然大量使用公有成员!在Java (一如其他面向对象语言),最佳实践通常是尽量保持各成员私有,并提供getter和setter。这就是封装,面向对象设计的基本概念之一。事实上,Play已经考虑到这一点,在自动生成getter和setter的同时保持封装;等下我们将看到它是怎么做到的。现在你可以刷新主页面,看一下结果。当然,除非你犯错,否则应该什么变化都看不到

7、:D。Play自动编译并加载了 User类,不过这没有给应用添加任何新特性。写下第一个测试测试新增的User类的一个好方法是写下JUnit测试用例。它会允许你增量开发的同时保证一切安好。要运行一个测试用例,你需要在test模式下运行应用。 停止当前正在运行的应用,打开命令行并输入:yobe gumounet ploy test* Rtnoirifl in test He* CtrlC to stopT III I J C)Listening fcr traftsrrt m.socket at aMrest:铮鮒 17:14:1515I7lll5t72517:l+il5f6301?:1+:15,

8、3611 :M 15,83617 d*:15,631n;i+;L5.97ZD$ play testapplicati on.conf已经存在一个默认的BasicTests.java ,):importorg.j un it.*;importplay.test.*;importmodels.*;当你在test mode 中运行Play应用时,Play会自动切换到test框架ID并加载对应的 。阅读框架ID文档来了解更多。在浏览器打开http:/localhost:9000/tests页面来看看测试运行器。尝试选择所有的默认测试并运行;应该全部都会是绿色但是默认的测试其实什么都没测 :DTests

9、 runnertha tMU to mn then国tan andThere is 1 unit test.1 functional test.and 1 selenium test.我们将使用JUnit测试来测试模型部分。如你所见,所以让我们打开它(/yabe/test/BasicTest.javaassertEquals(2, 1 + 1);publicclass BasicTest exte ndsUn itTestTest()public void aVeryImporta ntThi ngToTest删除没用的默认测试(aVerylmporta ntTh in gToTest),创建

10、一个注册新用户并进行检查的测试:Testpublic void createA ndRetrieveUser() / Create a new user and save itnew User( bob , secret , Bob ).save();/ Retrieve the user with e-mail address bobUser bob = User.fi nd(byEmail , bob ).first();/ TestassertNotNull(bob);assertEquals( Bob , bob.fullname);如你所见,Model父类给我们提供了两个非常有用的方

11、法:save()和find()。你可以在Play文档中的JPA支持阅读到Model类的更多方法。在test runner中选择BasicTests.java,点击开始,看一下是不是全都变绿了。我们将需要在User类中添加一个方法,来检查给用户的用户名和密码是否存在了。让我们 完成它,并且测试它。在 User.java 中,添加 connect() 方法:public static User connect (String email, String password) retur n find(byEmailA ndPassword, email, password).first();如今测试

12、用例成这样:Testpublic void tryC onn ectAsUser() / Create a new user and save itnew User( bob gmail .com , secret , Bob ).save();/ TestassertNotNull(User.connect (bob gmail .com , secret );assertNull(User.connect (bob gmail .com , badpassword );assertNull(User.connect (tom gmail .com , secret );每次修改之后,你都可

13、以从Play测试运行器运行所有的测试,来确保没有什么被破坏了。Post 类Post类表示博客文章。让我们写下代码: package models;import java.util.*;import javax.persistenee.*;import play.db.jpa.*;En titypublic class Post extends Model public String title;public Date postedAt;Lobpublic String content;Ma nyTo Onepublic User author;public Post (User author,

14、 String title, String content) this .author = author;this .title = title;this .content = content;this .postedAt = new Date();这里我们使用Lob注解告诉JPA来使用字符大对象类型(clob )来存储文章内容。我们也 声明跟User类的关系是ManyToOne。这意味着每个 Post对应一个User,而每个User可 以有多个Post。PostgreSQL的最近版本不会将 Lob注解的String成员存储成字符大对象类型,除非你额外用 Type(type = org.hib

15、ernate.type.TextType)注解该成员。我们将写一个新的测试用例来检查Post类能否正常工作。但在写下更多测试之前,我们需要修改下JUnit测试类。在当前测试中,数据库的内容永不删除,所以每次运行测试都会创 建越来越多的对象。假如将来我们需要测试对象的数目是否正确,这将会是一个问题。所以先写一个JUnit的setup()方法在每次测试之前清空数据库:public class BasicTestexte ndsUni tTest Beforepublic void setup () Fixtures.deleteDatabase();Before是JUnit测试工具的一个核心概念如

16、你所见,Fixtures类是一个在测试时帮助处理数据库的类。再次运行测试并检查是否一切安好。之后接着下下一个测试:Testpublic void createPost () / Create a new user and save itUser bob = new User( bob , secret , Bob ).save();/ Create a new postnew Post(bob, My first post , Hello world ).save();/ Test that the post has bee n createdassertEquals( 1, Post.co

17、un t();/ Retrieve all posts created by Bob,bob).fetch();List bobPosts = Post.fi nd(byAuthor/ TestsassertEquals( 1, bobPosts.size();Post firstPost = bobPosts.get (0);assertNotNull(firstPost);assertEquals(bob, firstPost.author);assertEquals( My first post , firstPost.title);assertEquals( Hello world,

18、firstPost.c onten t);assertNotNull(firstPost.postedAt);不要忘记导入java.util.List,否则你会得到一个编译错误。添加Comment 类最后,我们需要给博文添加评论功能。创建Comment类的方式十分简单直白。package models;import java.util.*;import javax.persistenee.*;import play.db.jpa.*;En titypublic classComment extendsModel public String author;public Date postedAt

19、;Lobpublic String content;Ma nyTo Onepublic Post post;publicComme nt(Post post, String author, Str ing content) this .post = post;this .author = author;this .content = content;this .postedAt = new Date();让我们写下第一个测试用例:Testpublic void postComments () / Create a new user and save itUser bob = new User(

20、 bob , secret , Bob ).save();/ Create a new postPost bobPost = new Post(bob, My first post , Hello world ).save ();/ Post a first comme ntNice post ).save();new Comme nt(bobPost,Jeffnew Comme nt(bobPost,Tom , I knew that !).save();/ Retrieve all comme ntsListvComme nt bobPostComme nts = Comme nt.fi

21、nd( etch();byPost , bobPost).f/ TestsassertEquals(2, bobPostComme nts.size();Comment firstComment = bobPostComments.get ( 0);assertNotNull(firstComme nt);assertEquals( Jeff, firstComme nt.author);assertEquals( Nice post , firstComme nt.c onten t); assertNotNull(firstComme nt.postedAt);Comme nt sec o

22、n dComme nt = bobPostComme nts.get ( 1);assertNotNull(sec on dComme nt);assertEquals( Tom , sec on dComme nt.author);assertEquals( I knew that !, sec on dComme nt.c onten t);assertNotNull(seco ndComme nt.postedAt);你可以看到Post和Comments 之间的联系并不紧密:我们不得不通过查询来获得所有跟 某一个Post关联的评论。通过在 Post和Comment类之间建立新的关系,我们

23、可以改善这 一点。在Post类添加comments成员:On eToMa ny( mappedBy=post , cascade=CascadeType.ALL)public List comme nts;public Post (User author, String title, String content) this .comments =new ArrayListvComment();this .author = author;this .title = title;this .content = content;this .postedAt = new Date();注意现在我们用

24、 mappedBy属性来告诉JPA Comment类的post成员是维持这个关系的一方。 当你用JPA定义一个双向关系时,需要指定哪一方来维持这个关系。在这个例子中,因为 Comment示例依赖于 Post,我们按 Comment.post 的反向来定义关系。我们也设置了 cascade属性来告诉JPA,我们希望Post的删除将级联影响到 comments。 也即是,如果你删除一个博文时,所有相关的评论也将一并删除。由于有了这个新关系,我们可以给Post类添加一个辅助方法来简化评论的添加:public Post addComme nt(Stri ng author, Str ing conte

25、nt) Comment newComment =new Comment( this , author, content).save();this .comments.add(newComment);this .save();return this ;让我们写多一个测试检查它能否工作:Testpublic void useTheComme ntsRelati on() / Create a new user and save itUser bob = new User( bob , secret , Bob ).save();/ Create a new post).savePost bobPo

26、st = new Post(bob, My first post , Hello world();/ Post a first comme ntbobPost.addComment(Jeff , Nice post );bobPost.addComment(Tom , I knew that !);/ Count thi ngsassertEquals(1, User.co un t();assertEquals(2, Comme nt.co un t();/ Retrieve Bobs postbobPost = Post.fi nd(byAuthor , bob).first();asse

27、rtNotNull(bobPost);/ Navigate to comme ntsassertEquals(2, bobPme nts.size();assertEquals(Jeff , bobPments.get (0).author);/ Delete the postbobPost.delete();/ Check that all comme nts have bee n deleted1, User.co un t();0, Post.cou nt();0, Comme nt.co un t();assertEquals(assertEquals(assertEquals(这次全

28、绿了么?Tests runnerSelKl tiw *m1s to run fwi dick 沁可 and 阿町ruThere is 1 unit test,使用Fixtures来写更复杂的测试当你开始写更加复杂的测试,你通常需要一些测试数据。Fixtures允许你在一个YAML文件 中描述你的模型,并在测试开始前加载。编辑 /yabe/test/data.yml并开始描述一个 User:User(bob):email : bobpassword : secretfull name : Bob呃,因为data.yml有点大,你可以在 这里下载它。现在我们可以创建一个加载数据并对它运行一些断言的

29、测试用例:Testpublic void fullTest () Fixtures .lo adModels(data.yml);/ Count thi ngsassertEquals(assertEquals(assertEquals(2, User.co un t();3, Post.cou nt();3, Comme nt.co un t();/ Try to connect as users assertNotNull(User.c onn ect( assertNotNull(User.c onn ect( assertNull(User.c onn ect( assertNull(

30、User.c onn ect(bob , secret );jeff , secret );jeffbadpassword);tom , secret );/ Find all of Bobs postsList bobPosts = Post.find( fetch();assertEquals( 2, bobPosts.size();author.email , bob)./ Fi nd all comme nts related to Bobs postsList bobComme nts = Comme nt.fi nd( b ).fetch();assertEquals( 3, bobComme nts.size();post.author.emailbo/ Find the most rece nt postPost fron tPost = Post.fi nd(order by postedAt desc).first();assertNotNull(fro ntPost);assertEquals( About the model layer ,

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论