第一篇:play手把手教你创建一个博客项目-07.使用CRUD实现基础的模型管理
07.使用CRUD设置一个基本的管理区域
当前,我们还没有在博客UI里为创建一篇新的博文或适当的评论提供方法。Play提供了一个开箱即用(out of the box)的CRUD模块,用于快速生成一个基本的管理区域。
允许CRUD模块
一个play应用程序可以由多个应用程序模块装配而成。这就允许我们在多个应用程序间重用组件或把一个大程序分散成几个小程序。
CRUD模块就是一个普通的应用程序,它通过内省(introspects)模型类来创建简单的列表或窗体。
为了能使用CRUD模块,需要在/conf/dependencies.yml文件里的require后添加一行代码: require:-play-> crud 接下来运行play dependencies命令,以确定新的模块依赖。
之后,在/yabe/conf/routers文件里添加下面这条路由就可以重用CRUD模块了(CRUD模块内建了一系列路由,因此需要导入进来): # Import CRUD routes * /admin module:crud 这条路由将把所有的CRUD内建路由导入到/admin前缀的 URL路径。你必须重新启动程序来获取新模块功能。
声明CRUD控制器
我们需要集成管理区域(administration area)的每个模型对象,都必须声明一个继承controllers.CRUD超类控制器的控制器。这非常简单。比如,为Post对象创建一个CRUD控制器的子类Posts控制器(/yabe/app/controllers/Posts.java)代码如下: package controllers;
import play.*;import play.mvc.*;
public class Posts extends CRUD { } 按照约定,模型类的CRUD控制器名称默认为模型类名加s(复数形式),通过这种方式,play将自动为每个控制器找到对应的模板对象。如果你需要使用一个不同的名称,你仍可以使用@CRUD.For注释,参考manual page。对其他模型对象而言,创建它的CRUD控制器完全相同: package controllers;
import play.*;import play.mvc.*;
public class Users extends CRUD { } package controllers;
import play.*;import play.mvc.*;
public class Comments extends CRUD { } package controllers;
import play.*;import play.mvc.*;
public class Tags extends CRUD { } 现在打开http://localhost:9000/admin/ URL,你就可以访问管理区域了。很快,你就会注意到在列表里的对象名称很粗糙,这是因为默认使用的是toString()来得到一个可读的模型对象呈现。
我们可以通过为所有模型对象提供适当的toString()实现方法来修订这个问题,比如对User类进行修订: „
public String toString(){ return email;} „
添加验证
这个生成的管理区域的主要问题是其窗体没有包含任何验证规则。事实上,CRUD模块能够从模板类的验证注释里提取验证规则。让我们为User类添加一些验证: package models;
import java.util.*;import javax.persistence.*;
import play.db.jpa.*;import play.data.validation.*;
@Entity public class User extends Model {
@Email @Required public String email;
@Required public String password;
public String fullname;public boolean isAdmin;„
现在,当你再次来到User模型对象的编辑或创建窗体时,你将看到验证规则已经自动增加到窗体了: 用同样的方法修改Post类: package models;
import java.util.*;import javax.persistence.*;
import play.db.jpa.*;import play.data.validation.*;
@Entity public class Post extends Model {
@Required public String title;
@Required public Date postedAt;
@Lob @Required @MaxSize(10000)public String content;
@Required @ManyToOne public User author;
@OneToMany(mappedBy=“post”, cascade=CascadeType.ALL)public List
@ManyToMany(cascade=CascadeType.PERSIST)public Set
检查一下运行结果: 在这里,你会看到一个有趣的效果: @MaxSize验证规则改变了play显示Post窗体的方式,它现在使用一个大的文本区域窗体组件来显示博文内容字段。最后,我们为Comment和Tag类添加验证规则: package models;
import java.util.*;import javax.persistence.*;
import play.db.jpa.*;import play.data.validation.*;
@Entity public class Tag extends Model implements Comparable
@Required public String name;„
package models;
import java.util.*;import javax.persistence.*;
import play.db.jpa.*;import play.data.validation.*;
@Entity public class Comment extends Model {
@Required public String author;
@Required public Date postedAt;@Lob @Required @MaxSize(10000)public String content;
@ManyToOne @Required public Post post;„
让窗体label标签更漂亮
正如你看到的一样,窗体label标签有点粗糙,play使用java字段名称来作为窗体标签。要想对会签进行定制,我们只需在/yabe/conf/messages文件里为标签提供更好的名称即可。事实上,你可以为每种语言支持提供一个独立的messages文件。比如,你可以用/yabe/conf/messages.fr文件来表示法语,详细情况参考本文第12节,Internationalisation and localisation。把下面这些标签添加到messages文件里: title=Title content=Content postedAt=Posted at author=Author post=Related post tags=Tags set name=Common name email=Email password=Password fullname=Full name isAdmin=User is admin 然后刷新窗体看看效果: 定制 ‘Comments’ 数据列表
CRUD模块可以完全进行定制,比如,如果你看一下评论列表页面,你就会发现数据列表的方式并不太好,我们将为其添加一个列,比如用‘related post’列来帮助我们快速过滤列表。事实上,作为应用程序的“主人”,你完全可以重写任何CRUD模块提供的action 或模板。比如,如果我们打算定制 ‘评论列表’视图页面,我们只需提供另外一个/yabe/app/views/Comments/list.html模板文件即可。
CRUD模块提供了许多play命令,其中crud:ov命令用于重写任何模板,命令如下:
$ play crud:ov--template Comments/list 现在你就所有一个一新的模板/yabe/app/views/Comments/list.html: #{extends 'CRUD/layout.html' /}
&{'crud.list.title', type.name}
#{crud.search /}
第二篇:play手把手教你创建一个博客项目-08.添加身份认证
08.添加身份认证
在上一节是,我们为应用程序添加了管理区域(administration area)功能,现在我们将在这些管理区域中插入一些身份认证功能。幸运的是,play已经为这个功能准备了一个模块,这个模块叫Secure(安全)。
在程序里允许使用Secure模块
在yabe/conf/application.conf文件里允许使用Secure模块,并重启程序: # Import the secure module module.secure=${play.path}/modules/secure 重启后,play应用在控制台显示模块已经成功启动的相关信息。
Secure模块带有一系列默认的路由,需要在yabe/conf/routes里引入(或定义自己的路由也行): # Import Secure routes * / module:secure 保护admin(此处指需要身份认证的)控制器
安全模块提供了一个controllers.Secure控制器,它声明了所有可能用到的拦截器。当然,我们可以以继承这个控制器的方法获得其拦截器,但是java只允许单继承,这就导致了一些问题。
为了避免单继承带来的限制,我们可以用@With来注释admin控制器,以告诉play去调用相应的拦截器:
package controllers;
import play.*;import play.mvc.*;
@With(Secure.class)public class Posts extends CRUD { } 同样用于Comments, Users和Tags控制器。
Now if you try to access any admin action, you should get a log-in page: 事实上,现在你就可以试着输入任意username/password对看看,它其实并没有对身份进行认证。
定制身份认证处理
应用程序必须提供一个controllers.Secure.Security实例来定制身份认证处理。通过继承这个类来创建我们自己版本的Secure类,我们可以指定如何对用户身份进行认证。
创建yabe/app/controllers/Security.java文件,重写authenticate()方法: package controllers;
import models.*;
public class Security extends Secure.Security {
static boolean authenticate(String username, String password){ return true;} } 既然我们已经拥有了User对象,那么就非常容易实现这个方法: static boolean authenticate(String username, String password){ return User.connect(username, password)!= null;} 现在打开http://localhost:9000/logout进行登录尝试,用户名和密码在initial-data.yml文件里定义,比如bob@gmail.com/secret。
重构管理区域(administration area)
我们之前已经使用CRUD模块来实现管理区域,但是这个管理区域仍然没有集成到博客UI里,接下来我们将在一个新的管理区域上开始工作。这个新的管理区域允许每个作者访问他自己的博客。而超级用户则继续使用完整功能的管理区域。
接下来,让我们为管理部分创建一个新Admin控制器: package controllers;
import play.*;import play.mvc.*;
import java.util.*;
import models.*;
@With(Secure.class)public class Admin extends Controller {
@Before static void setConnectedUser(){ if(Security.isConnected()){ User user = User.find(“byEmail”, Security.connected()).first();renderArgs.put(“user”, user.fullname);} }
public static void index(){ render();} } 重构路由定义yabe/conf/routes: # Administration GET /admin/? Admin.index * /admin module:crud 请注意路由的顺序,第一行就匹配了的http请求相应的action会率先使用,同时忽略在其之下的路由配置。也就是说Admin控制器必须位于第二行之上,第二条路由将匹配所有其他的/admin请求,用于调用CRUD模块页面,否则/admin/将映射到CRUD.index而不是Admin.index。
现在把yabe/app/views/main.html模块里的 ‘Log in to write something’文本修改到Admin.index控制器action:
…
…最后一件事就是为yabe/app/views/Admin/index.html模板文件完成所有的填充工作,让我们从简单的开始: Welcome ${user}!现在回到主页,单击 ‘Log in to write something’链接就回进入样的管理区域页面: 非常好!但是既然我们已经有几个管理区域的页面,那么,我们就应该有一个超级模板以重用代码,让我们创建一个yabe/app/views/admin.html模板:
#{get 'moreStyles' /}
第三篇:play手把手教你创建一个博客项目-03.构建第一个页面
03.构建第一个页面
之前,我们已经编写好了数据模型,是时候为应用程序创建第一个页面了。这个页面只显示当前发表的博文完整内容,同时显示之前发表的博文列表。下面是该页面结构示意图:
在启动时加载默认数据
事实上,在编写第一个页面之前,我们还需要做一些工作。在一个没有任何测试数据的页面上进行工作并不太好,你甚至不能进行任何测试。
为博客程序注入测试数据的一条途径就是在应用程序启动时加载一个固定文件。为了实现这个目的,我们将创建一个引导任务(Bootstrap Job)。一个play job 任务就是一在没有任何http请求的情况下执行一些特定工作,比如在应用程序启动时或指定时间间隔时使用CRON任务。
接下来,让我们创建/yabe/app/Bootstrap.java job文件,使用Fixtures加载一系列默认数据:
import play.*;import play.jobs.*;import play.test.*;
import models.*;
@OnApplicationStart public class Bootstrap extends Job {
public void doJob(){ // 检查数据库是否为空 if(User.count()== 0){ Fixtures.loadModels(“initial-data.yml”);} } } 在这里,我们使用@OnApplicationStart来注释这个Job,用于告诉play我们打算在应用程序启动时同步运行这个任务。
事实上,在DEV和PROD模式下,这个任务的运行情况有所不同。在DEV模式下,play会等待第一个请求达到时才运行任务。因此这个任务会在第一个请求到达时才同步执行,也就是说,如果这个任务失败,你会在浏览器里看到错误消息。在PROD模式里,这个任务将会在应用程序启动时就执行(与play run命令同步),以防止应用程序在启动时发生错误。
你必须在yabe/conf/下创建一个initial-data.yml文件。当然,你也可以重用我们之前在data.yml里定义的内容。
博客主页
这次,我们将真正开始编写主页代码。
还记得程序的第一个页面是如何显示的吗?首先是在routes文件里指定/ URL 将调用controllers.Application.index()action方法,然后这个index()调用render()方法渲染/yabe/app/views/Application/index.html模板。我们将保留这些组件,但是我们会在其中添加代码来加载博文列表并显示。打开/yabe/app/controllers/Application.java控制器并修改index()action来加载博文列表:
package controllers;
import java.util.*;
import play.*;import play.mvc.*;
import models.*;
public class Application extends Controller {
public static void index(){ Post frontPost = Post.find(“order by postedAt desc”).first();List
olderPosts = Post.find(“order by postedAt desc”).from(1).fetch(10);render(frontPost, olderPosts);} } 看到我们是如何向render方法传递对象的吗?通过这种方式,我们就可以在模板里使用相同的名称来访问这些对象了。在上面的代码里,我们在模板里就可以直接使用变量frontPost和olderPosts。
打开/yabe/app/views/Application/index.html并修改,用于显示这些对象: #{extends 'main.html' /} #{set title:'Home' /}
#{if frontPost}