11.2.1 使用CRUD模块#
启用CRUD模块
CRUD是Play内置的模块,不用进行安装,只需在/conf/application.conf文件中添加如下配置,就可以将其引入:
#The CRUD module module.crud=${play.path}/modules/crud
引入默认CRUD路由
配置/conf/routes文件,引入CRUD模块默认路由:
# Import CRUD routes * /admin module:crud
并不是只能采用默认的路由配置,还可以自定义路由或者两者混用。
创建User类
CRUD模块为域模型提供方法接口,首先创建User类:
package models; import play.*; import play.db.jpa.*; import javax.persistence.*; import java.util.*; @Entity public class User extends Model { public String name; public String email; public String address; }
创建Users控制器
创建简单的控制器Users,继承CRUD模块提供的父类控制器,CRUD模块将通过Users进行路由调度:
package controllers; public class Users extends CRUD { }
继承CRUD时,可能会出现无法引入模块的错误。错误的原因是由IDE导致的,并不影响模块的使用。
解决方案(Eclipse中引入CRUD模块为例):手动配置IDE引入模块。右击应用程序 -> New->Folder -> Folder name中输入crud -> 点击Advanced -> 选择Link to folder in the file system -> 路径选择modules\crud\app -> 单击Finish -> 使用play eclipsify命令使项目重新工程化。重启Eclipse后错误消失。
访问http://localhost:9000/admin就可以看到管理域,如图11.1所示。
(图11.1 管理域)
控制器(Users)默认采用域模型复数形式命名,即域模型名(User)结尾加上字母“s”。如果想使用其他的名称,需要用到@CRUD注解:
package controllers; import models.User; @CRUD.For(User.class) public class AdminUsers extends CRUD { }
User表单
点击管理域中的Add按钮,会呈现添加User的表单,如图11.2所示:
(图11.2 User表单)
目前添加User的功能并不完善,需要为User类增加一些验证规则:
package models; import play.*; import play.db.jpa.*; import javax.persistence.*; import java.util.*; import play.data.validation.*; @Entity public class User extends Model { @Required @MinSize(8) public String name; @Required @Email public String email; @Required @MaxSize(1000) public String address; public String toString() { return email; } }
刷新浏览器,就可以看到验证已经自动生效,如图11.3所示。
(图11.3 添加验证的User表单)
改变表单的label
在应用的conf/messages文件中增加如下配置,定制表单的label:
name=Name email=Email address address=Postal address
刷新浏览器,定制效果如图11.4所示。
(图11.4 定制label后的User表单)
自定义列表视图
使用CRUD管理域创建一个User。User实体的name属性值为:Guillaume,email属性值为:guillaume.bort@gmail.com。默认的列表视图中只有一列,如图11.5所示。这是因为CRUD模块默认调用模型对象的toString()方法显示返回结果。
(图11.5 默认视图)
如要希望增加列表视图中显示的属性列的个数,需要在应用中创建/app/views/Users/list.html模板。Play提供的play crud:ov命令可以完成这个操作,打开控制台,进入应用目录并输入play crud:ov命令(例子中应用名为test,在D:\play\路径下):
D:\play>cd test D:\play\test>play crud:ov --template Users/list ~ _ _ ~ _ __ | | __ _ _ _| | ~ | '_ \| |/ _' | || |_| ~ | __/|_|\____|\__ (_) ~ |_| |__/ ~ ~ play! 1.2, http://www.playframework.org ~ ~ Copied D:\play\modules\crud\app/views/CRUD/list.html to D:\play\test\a pp/views/Users/list.html ~
play crud:ov命令将CRUD模块中的默认模板list.html复制到应用的app/views/Users/目录下。如果该文件已经存在,会将其覆盖。修改app/views/Users/list.html模板:
#{extends 'CRUD/layout.html' /} <div id="crudList" class="${type.name}"> <h2 id="crudListTitle">&{'crud.list.title', type.name}</h2> <div id="crudListSearch"> #{crud.search /} </div> <div id="crudListTable"> #{crud.table fields:['email', 'name'] /} </div> <div id="crudListPagination"> #{crud.pagination /} </div> <p id="crudListAdd"> <a href="@{blank()}">&{'crud.add', type.modelName}</a> </p> </div>
修改#{crud.table}标签,列表视图将显示email,name两个属性列。刷新浏览器,效果如图11.6所示。
(图11.6 自定义列表视图)
使用#{crud.custom}标签定义更多功能
CRUD模块提供的#{crud.custom}标签可以对User实体中的每个字段进行定义,并以此控制列表视图和表单视图的显示方式:
#{crud.table fields:['name', 'company']} #{crud.custom 'company'} <a href="@{Companies.show(object.company.id)}"> ${object.company.name} </a> #{/crud.custom} #{/crud.table}
也可以为列表视图定义额外的显示列,或者为表单视图中定义额外的表单输入:
#{crud.table fields:['name', 'company', 'edit']} #{crud.custom 'company'} <a href="@{Companies.show(object.company.id)}">${object.company.name}</a> #{/crud.custom} #{crud.custom 'edit'} <a href="@{Users.edit(object.id)}">Edit</a> #{/crud.custom} #{/crud.table}
11.2.2 集合或数组的显示方式#
CRUD模块在列表视图中以文本字段的形式显示实体属性,如果实体属性是数组或者集合的形式,将以逗号分隔:
@Entity public class Account extends Model { @CollectionOfElements public Set<ContentType> contentTypes; @CollectionOfElements public Set<String> usernames; public Account(Set<String> usernames) { super(); this.usernames = usernames; } }
在视图列表中,contentTypes属性将会显示为:myEnumId1,myEnumId2,usernames属性将会显示为string1,string2。
11.2.3 自定义show视图和blank视图#
ObjectType类在 CRUD模块中的影响至关重要,它可以控制视图行为。因此如果希望改变 CRUD模块行为,可以创建自己的ObjectType类,并在控制器或者控制器的父类中定义相应的静态方法。protected static ObjectType createObjectType(Class<? extends Model> type) { return new VersionObjectType(type); }
下例将创建自己的ObjectType类,使用@Version注解将域隐藏:
public class CustomAdminCompany extends CRUD { protected static ObjectType createObjectType(Class<? extends Model> type) { return new VersionObjectType(type); } public static class VersionObjectType extends ObjectType { private final String versionColumn; public VersionObjectType(Class<? extends Model> modelClass) { super(modelClass); versionColumn = getVersionColumnName(modelClass); } private String getVersionColumnName(Class modelClass) { Class c = modelClass; try { while (!c.equals(Object.class)) { for (Field field : c.getDeclaredFields()) { if (field.isAnnotationPresent(Version.class)) { return field.getName(); } } c = c.getSuperclass(); } } catch (Exception e) { throw new UnexpectedException("Error while determining the " + "object @Version for an object of type " + modelClass); } return null; } @Override public List<ObjectField> getFields() { List<ObjectField> result = super.getFields(); for (ObjectField objectField : result) { if (objectField.name.equals(versionColumn)) { objectField.type = "hidden"; } } return result; } } }
到此并没有结束,还可以自定义findPage()等其他方法。
11.2.4 CRUD模块命令#
CRUD模块提供了crud:override命令,用于重写默认的模板。执行该命令CRUD会自动加载模块模板,如果应用程序模板已存在,会将其覆盖。crud:ov命令与crud:override命令等价,可以替代使用。
以下命令会将指定模板(如Users/list.html)拷贝至应用程序的app/views/CRUD/目录。可以使用-t替代--template,简化命令的使用。
play crud:override --template [path]
以下命令重写主页面中的布局模板layout.html。
play crud:override –-layout
以下命令重写样式表crud.css,并将其拷贝至public/stylesheets/目录。
play crud:override –-css
11.2.5局限性#
CRUD模块虽然提供强大的功能,但还是有自身的局限性。如果两个实体之间存在双向关系,CRUD模块只能表现其中的一个(没有标注mappedBy属性)。