Play 2.0以上 框架
数据库是整个站点的数据储藏室。用户提交的数据可以存储在数据库中,以便未来使用。Play可以通过JDBC和数据库通信。我讲介绍Play和mysql数据库的连接。
Play 2.*版本的默认操作数据库的方式是通过Ebean。Play提供Finder这一帮助类型,可以实现一些简单的数据库查询。
数据库准备
在mysql中增加数据库testing。增加用户"player",密码为"player"。为用户player增加适当的权限。
CREATE DATABASE testing DEFAULT CHARACTER SET utf8; CREATE USER 'player'@'localhost' IDENTIFIED BY 'player'; GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES ON testing.* TO 'player'@'localhost';
为了在Play中使用mysql数据库,需要在conf/application.conf中增加设置:
# Database configuration db.default.driver=com.mysql.jdbc.Driver db.default.url="jdbc:mysql://127.0.0.1:3306/testing" db.default.user="player" db.default.password="player"
# Ebean configuration ebean.default="models.*"
还需要修改build.sbt为:
name := "test" version := "1.0-SNAPSHOT" libraryDependencies ++= Seq( javaJdbc, javaEbean, cache, "mysql" % "mysql-connector-java" % "5.1.18" ) play.Project.playJavaSettings
上面的改动完成后,使用play run来运行服务器。
创建模型
下面,我在模型中增加一个实体(entity),即一个Person类。放入models/Person.java
package models; import java.util.List; import javax.persistence.Entity; import javax.persistence.Id; import play.db.ebean.Model; import play.db.ebean.Model.Finder; @Entity public class Person extends Model { @Id public Integer id; public String name; // Query public static Finder<Integer,Person> find = new Finder<Integer,Person>(Integer.class, Person.class); public static List<Person> findAll() { return find.all(); } public static Person findByName (String name) { return find.where().eq("name", name).findUnique(); } }
Person类继承自Model类,并有一个@Entity的注解,从而说明它是模型中的一个实体。实体有两个场,整数的id和字符串的name,用来保存数据。
@id注解下,id将不为空,不重复,并自动增加。
Person还有一个静态的场find。find是Play提供的Finder类型,用于数据库查询。而Person类中得findAll()和findByName()的静态方法中,就调用了find,从而在数据库中查询条目。
Play有evolution模块,管理数据库的表。写好Person.java后,访问项目。Play这时会生成在mysql中建立表格的脚本。运行该脚本即可。
增加数据库条目
增加一个动作。这个动作向数据库增加条目:
public static Result addPerson() { Person p1 = new Person(); Person p2 = new Person(); p1.name = "vamei"; p2.name = "play"; p1.save(); p2.save(); return ok("Saved"); }
*** 上面的代码要import models.Person。
将/addPerson这一URL对应该动作。访问后,数据库将增加条目:
练习 根据表单一讲的内容,增加一个向数据库添加条目的表单。
数据库查询
我可以在动作中调用刚才定义的查询方法findAll()和findByName(),比如增加allPerson()动作:
public static Result allPerson() { List<Person> persons = Person.findAll(); return ok(views.html.personList.render(persons)); }
上面查询得到的Person类型的表,传递给模板views/personList.scala.html:
@(personList: List[models.Person]) <!DOCTYPE html> <html> <body> <ul> @for(person <- personList) { <li>@person.name</li> } </ul> </body> </html>
修改routes,增加对应的URL为/allPerson,页面如下:
事实上,我也可以在动作中直接调用Person.find,来组成查询语句。这将让动作内部有更大的查询自由度。比如上面的动作可以改写成:
public static Result allPerson() { List<Person> persons = Person.find.all(); return ok(views.html.personList.render(persons)); }
使用模板
我首先创建一个模板,纯粹起视图功能。在app/views文件夹中,新建文件index.scala.html (如果已有,则删除并重新创建)。
<!DOCTYPE html> <html> <header> <title>Play</title> </header> <body> <p>Hello World! Start using the Template.</p> </body> </html>
这个模板是个纯粹的html文件,是最简单的模板形式。
修改app/controllers/Application.java:
package controllers; import play.*; import play.mvc.*; public class Application extends Controller { public static Result index() { return ok(views.html.index.render()); } }
ok()中接收的是views.html.index.render(),实际上就是app/views/index.scala.html这一模板的render()方法。Play会根据模板,自动生成相应的类。
*** 也可以用import引入views.html.index,而不是使用完整的类路径。
访问页面:
模板语言
这一部分,我把对象作为参数传给模板,然后在模板中显示对象中包含的数据。修改index.scala.html:
@(title: String, content: String) <!DOCTYPE html> <html> <header> <title>@title</title> </header> <body> <p>@(content) Start using the template.</p> </body> </html>
上面的第一行,以@符号开头,说明了该模板所接收的两个参数,即String类型的title和content。在模板中,用@符号和参数名,来调用参数。参数名周围可以用括号"()",以区分正文。
修改动作:
public static Result index() { return ok(views.html.index.render("Play", "Hello World! Parameters passed. ")); }
这里传递两个字符串给模板。最终显示的结果中,两个字符串将填充在模板中的适当位置。
上面把一个对象传递给模板。我们还可以在模板中调用对象的属性或方法:
@object.method()
@object.field
模板控制
我还可以用Scala的语法,在模板中实现更复杂的逻辑。比如下面的模板中使用循环:
@(title: String, content: String, lines: List[String]) <!DOCTYPE html> <html> <header> <title>@title</title> </header> <body> <p>@(content) Start using the template.</p> <ul> @for(line <- lines) { <li>@line</li> } </ul> </body> </html>
循环是@for实现的。@后面不仅可以是一个对象,还可以是一个完整的Scala语法。
修改动作,把一个字符串类型的表作为参数传递给模板:
package controllers; import play.*; import play.mvc.*; import java.util.List; import java.util.ArrayList; public class Application extends Controller { public static Result index() { List<String> lines = new ArrayList<String>(); lines.add("a"); lines.add("b"); lines.add("c"); return ok(views.html.index.render("Play", "Hello World!", lines)); } }
得到下面的页面:
模板中还可以有if选择结构,比如
@if(item) { <p>True</p> } else { <p>False</p> }
根据参数item的真假,if结构显示不同的内容。
其它
在@* *@中加入注释
由于@的特殊功能,为了在模板中显示"@"字符,需要使用@@。
表 3. 模板中可用的动态元素
${...} | 用来对一个表达式进行求值。如 ${note.title} 的值是领域对象 note 的属性 title 的值。 |
@{...} 和@@{...} | 用来生成调用控制器中动作方法的 URL,可以用在页面的链接中。@{...} 和 @@{...} 生成的分别是相对 URL 和绝对 URL。如 <a href="@{Application.index()}"> 首页 </> 生成一个指向首页的链接。 |
&{...} | 用来显示经过国际化之后的消息内容。 |
*{...}* | 用来添加注释。如 *{ 这是注释 }* 。 |
%{...}% | 用来添加复杂的 Groovy 脚本,可以声明变量和添加语句。 |
#{...} | 用来调用 Play 框架的或是开发人员自定义的标签。 |