play框架使用起来(18)
2016-11-04 18:15
274 查看
1、集成OpenID
OpenID是身份识别系统,具有开放,非集中等特点。我们只需要记录OpenID授权用户的使用信息,不必保持用户的特定状态,就可以在程序中很容易地识别新用户。
补充:
OpenID是去中心化的网上身份认证系统。对于支持OpenID的网站,用户不需要记住像用户名和密码这样的传统验证标记。取而代之的是,他们只需要预先在一个作为OpenID身份提供者(identity provider, IdP)的网站上注册。OpenID是去中心化的,任何网站都可以使用OpenID来作为用户登录的一种方式,任何网站也都可以作为OpenID身份提供者。OpenID既解决了问题而又不需要依赖于中心性的网站来确认数字身份。
下面实例将演示在Play应用中如何使用OpenID认证,以下是OpenID认证过程:
针对每个用户请求,先检查用户是否已经连接OpenID。
如果用户没有连接OpenID,跳转至用户可以提交OpenID的页面。
将用户提交的OpenID重定向到OpenID提供商。
返回后,得到验证通过的OpenID用户信息,并将它保存在HTTP Session中。
Play中的OpenID功能由play.libs.OpenID辅助类提供,基于OpenID4Java实现。我们在控制器中定义authenticate()方法,处理用户提交的OpenID。该方法先进行用户OpenID的检查,如果已经连接,则将用户信息保存在HTTP Session中,并显示欢迎页面。如果用户是第一次提交OpenID,则将提交的OpenID重定向到OpenID提供商:
创建Login.html模板,添加用户提交OpenID的表单:
最后定义路由:
2、Ajax请求
Play默认集成了jQuery库,并将其存放于应用的public/javascripts目录。框架对jQuery进行了封装,提供#{jsAction /}标签简化了请求异步调用控制器中的Action方法,因此我们可以通过jQuery非常方便地处理Ajax请求。
本节将以简单的Ajax应用为例,介绍在Play框架中如何使用jQuery提供的Ajax支持。
Play提供的#{jsAction /}标签会返回一个JavaScript函数,该JavaScript函数由基于Action方法的URL连接和自由变量组成。它并不会自动执行Ajax请求,而需要我们先手动对返回的URL进行配置。
下面介绍Play应用的Ajax实例。首先在控制器Hotels中定义Action方法list,用于处理浏览器异步提交的请求。list方法定义完成后为其配制路由规则:
我们在客户端中可以通过以下方式导入路由:
在这个例子中,我们向Hotels控制器中的list方法发送请求,请求中包含search,size和page三个参数。之后将请求保存在listAction变量中,使用load函数通过jQuery处理该请求(这里处理的是HTTP GET请求)。以下就是所发送请求的具体URL:
以这种方式发送请求会返回HTML数据。当然,我们也可以在控制器中使用适当的渲染方法,返回其他格式的数据,比如renderJSON, renderXML或者直接使用XML的模版等。在客户端接收到JSON或者XML数据后,可以通过jQuery进行格式转换。如果读者还想了解更多细节问题,可以查阅jQuery相关内容。
如果读者需要使用POST请求,只需要将jQuery方法进行转换即可:
Play提供的#{jsRoute /}标签,可以帮助开发者更好地管理路由。#{jsRoute /}标签的使用方法很简单,并且与#{jsAction /}类似,但是不同的地方为#{jsRoute /}标签返回的是一个对象。该对象包含基于服务端Action的URL,以及相应的HTTP方法(GET、POST等),具体范例如下所示。
使用#{jsRoute /}标签所带来的好处是显而易见的,开发者只需要修改routes路由文件,就可以统一地改变HTTP方法,而不再需要一个一个查看和修改模板文件了。
[b]3、[b]管理数据库升级[/b]
[/b]
开发人员使用关系数据库时,通常需要跟踪和管理数据库结构的升级和变化。当出现以下几种情况时,我们需要使用更成熟的方式跟踪和管理数据库结构的变化:
在团队开发中,每个成员都需要知道数据库结构的任何变化。
当成品部署到服务器上后,需要采用安全稳定的方式去升级数据库结构。
当开发人员在不同的机器上工作时,需要保持数据库同步。
注意:
如果采用JPA进行操作,Hibernate会自动处理数据库结构的升级。如果读者经常需要手动管理数据库结构,并进行一些精细的调整,版本控制就变得必不可少了。
Play通过编写升级脚本来跟踪数据库结构的变化。这些脚本采用标准的SQL语句作为语法规则,存放在应用程序的db/evolutions目录下。脚本使用统一的命名规则:编写的第一个脚本命名为1.sql,第二个脚本为2.sql,并以此类推。每个脚本都包含两个部分:
Ups部分用于描述需要改变的地方。
Downs部分用于描述如何还原。
以下是数据库升级脚本的例子,起到引导作用:
注意:
在编写数据库升级脚本时,须使用注释明确地将Ups和Downs部分区分开。
如果读者已经在application.conf文件中配置了数据库,并且编写了数据库升级脚本(放置在db/evolutions目录下),应用在启动时就会自动激活数据库的升级模式。我们也可以强制将其关闭,只需在application.conf文件中进行如下配置:
一旦数据库的升级模式被激活,框架会执行升级管理。当应用处于DEV模式,Play会在请求到达时检查数据库的结构,如果数据库结构不是最新的,将显示错误页面,并建议使用合适的SQL脚本同步数据库,如图1所示。如果应用处于PROD模式,Play则会在整个应用启动之前进行检查。
![](http://www.playframework.cn/attach/%E7%AE%A1%E7%90%86%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8D%87%E7%BA%A7/evolutions.png)
(图1 数据库结构不同步)
在页面上点击Apply evolutions按钮,就可以直接执行SQL升级脚本。
补充:
如果应用使用内存数据库(db=mem),Play会预先对数据库进行检测。如果数据库为空就会自动执行所有的升级脚本。
协作开发中,保持应用同步非常重要。设想一下,如果有两个开发者合力开发项目,开发者A因为自己负责的功能模块需要,创建了新的数据表并编写了升级脚本2.sql:
Play会将该升级脚本应用于开发者A的数据库。与此同时,开发者B因功能需求修改了User表,也编写了升级脚本,同样命名为2.sql:
开发者B先完成了负责的功能模块,并提交了代码(比如开发者采用Git进行管理)。开发者A需要先整合两个人前半段的工作结果,才能开展后续工作,但是在执行git pull的时候,合并会出现如下冲突:
这是因为开发者A和开发者B都创建了2.sql升级脚本,必须进行整合:
整合工作非常简单,只需要将冲突的部分合并即可:
将整合后的脚本命名为2.sql,作为升级脚本的最新修订版(注意:与前期开发者A应用到数据库的2.sql不同)。Play会发现这个情况,并询问开发者A是否同步数据库,将最新的修订版2.sql替换原来的版本,如图2所示。
![](http://www.playframework.cn/attach/%E7%AE%A1%E7%90%86%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8D%87%E7%BA%A7/evolutions-conflict.png)
(图2 同步升级脚本)
如果脚本(比如3.sql)中存在错误,数据库升级工作将无法完成。当出现这种情况时,Play会将数据库的结构标记为非同步状态,并要求我们手动解决这个问题,之后才能继续别的操作。下例的Ups部分存在错误:
该脚本在执行时会出现错误,Play将数据库的结构标记为非同步状态,如图3所示:
![](http://www.playframework.cn/attach/%E7%AE%A1%E7%90%86%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8D%87%E7%BA%A7/evolutions-inconsistent.png)
(图3非同步状态)
错误必须得到修正后,才能进行后续操作。使用SQL命令手动更改数据库结构:
然后点击Mark it resolved按钮,通知框架问题已经解决。由于原先的升级脚本存在错误,必须将其修正。修改3.sql脚本文件:
Play会发现该升级脚本是最新的,因此覆盖原有的3.sql执行,如图4所示:
![](http://www.playframework.cn/attach/%E7%AE%A1%E7%90%86%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8D%87%E7%BA%A7/evolutions-resolve.png)
(图4 成功执行数据库结构同步)
图4 所显示的是脚本正确执行的结果,之后可以继续别的工作。
补充:
介绍一个开发小技巧:开发人员可以在每次开发前手动删除原有的数据库,当应用启动时框架就会自动加载所有的升级脚本。这样做的好处是可以使开发人员的数据库一直保持最新版本。
当应用处于DEV模式时,数据库升级是交互式地进行的。但是在PROD模式下,必须先使用play evolutions命令将数据库结构升级为最新版本,才可以开启应用。当框架发现应用程序的数据库不是最新版本时,控制台会出现如下错误信息:
该错误信息提示我们运行play evolutions命令同步数据库:
使用play evolutions:apply命令可以通知Play自动执行数据库升级脚本:
如果在成品数据库上手动执行脚本,可以使用play evolutions:markApplied命令通知Play该数据库已经是最新版本了:
当应用处于DEV模式,如果框架自动执行升级脚本失败,就需要手动解决,并将数据库结构标记为已修正的:
OpenID是身份识别系统,具有开放,非集中等特点。我们只需要记录OpenID授权用户的使用信息,不必保持用户的特定状态,就可以在程序中很容易地识别新用户。
补充:
OpenID是去中心化的网上身份认证系统。对于支持OpenID的网站,用户不需要记住像用户名和密码这样的传统验证标记。取而代之的是,他们只需要预先在一个作为OpenID身份提供者(identity provider, IdP)的网站上注册。OpenID是去中心化的,任何网站都可以使用OpenID来作为用户登录的一种方式,任何网站也都可以作为OpenID身份提供者。OpenID既解决了问题而又不需要依赖于中心性的网站来确认数字身份。
下面实例将演示在Play应用中如何使用OpenID认证,以下是OpenID认证过程:
针对每个用户请求,先检查用户是否已经连接OpenID。
如果用户没有连接OpenID,跳转至用户可以提交OpenID的页面。
将用户提交的OpenID重定向到OpenID提供商。
返回后,得到验证通过的OpenID用户信息,并将它保存在HTTP Session中。
Play中的OpenID功能由play.libs.OpenID辅助类提供,基于OpenID4Java实现。我们在控制器中定义authenticate()方法,处理用户提交的OpenID。该方法先进行用户OpenID的检查,如果已经连接,则将用户信息保存在HTTP Session中,并显示欢迎页面。如果用户是第一次提交OpenID,则将提交的OpenID重定向到OpenID提供商:
@Before(unless={"login", "authenticate"}) static void checkAuthenticated() { if(!session.contains("user")) { login(); } } public static void index() { render("Hello %s!", session.get("user")); } public static void login() { render(); } public static void authenticate(String user) { if(OpenID.isAuthenticationResponse()) { UserInfo verifiedUser = OpenID.getVerifiedID(); if(verifiedUser == null) { flash.error("Oops. Authentication has failed"); login(); } session.put("user", verifiedUser.id); index(); } else { if(!OpenID.id(user).verify()) { // will redirect the user flash.error("Cannot verify your OpenID"); login(); } } }
创建Login.html模板,添加用户提交OpenID的表单:
#{if flash.error} <h1>${flash.error}</h1> #{/if} <form action="@{Application.authenticate()}" method="POST"> <label for="user">What’s your OpenID?</label> <input type="text" name="user" id="user" /> <input type="submit" value="login..." /> </form>
最后定义路由:
GET / Application.index GET /login Application.login * /authenticate Application.authenticate
2、Ajax请求
2.1 集成jQuery#
Play默认集成了jQuery库,并将其存放于应用的public/javascripts目录。框架对jQuery进行了封装,提供#{jsAction /}标签简化了请求异步调用控制器中的Action方法,因此我们可以通过jQuery非常方便地处理Ajax请求。本节将以简单的Ajax应用为例,介绍在Play框架中如何使用jQuery提供的Ajax支持。
2.2 使用#{jsAction /}#
Play提供的#{jsAction /}标签会返回一个JavaScript函数,该JavaScript函数由基于Action方法的URL连接和自由变量组成。它并不会自动执行Ajax请求,而需要我们先手动对返回的URL进行配置。下面介绍Play应用的Ajax实例。首先在控制器Hotels中定义Action方法list,用于处理浏览器异步提交的请求。list方法定义完成后为其配制路由规则:
GET /hotels/list Hotels.list
我们在客户端中可以通过以下方式导入路由:
<script type="text/javascript"> var listAction = #{jsAction @list(':search', ':size', ':page') /} $('#result').load( listAction({search: 'x', size: '10', page: '1'}), function() { $('#content').css('visibility', 'visible') } ) </script>
在这个例子中,我们向Hotels控制器中的list方法发送请求,请求中包含search,size和page三个参数。之后将请求保存在listAction变量中,使用load函数通过jQuery处理该请求(这里处理的是HTTP GET请求)。以下就是所发送请求的具体URL:
GET /hotels/list?search=x&size=10&page=1
以这种方式发送请求会返回HTML数据。当然,我们也可以在控制器中使用适当的渲染方法,返回其他格式的数据,比如renderJSON, renderXML或者直接使用XML的模版等。在客户端接收到JSON或者XML数据后,可以通过jQuery进行格式转换。如果读者还想了解更多细节问题,可以查阅jQuery相关内容。
如果读者需要使用POST请求,只需要将jQuery方法进行转换即可:
$.post(listAction(), function(data) { $('#result').html(data); });
2.3 使用#{jsRoute /}#
Play提供的#{jsRoute /}标签,可以帮助开发者更好地管理路由。#{jsRoute /}标签的使用方法很简单,并且与#{jsAction /}类似,但是不同的地方为#{jsRoute /}标签返回的是一个对象。该对象包含基于服务端Action的URL,以及相应的HTTP方法(GET、POST等),具体范例如下所示。<script type="text/javascript"> var updateUserRoute = #{jsRoute @Users.update(':id') /} $.ajax({ url: updateUserRoute.url({id: userId}), type: updateUserRoute.method, data: 'user.name=Guillaume' }); </script>
使用#{jsRoute /}标签所带来的好处是显而易见的,开发者只需要修改routes路由文件,就可以统一地改变HTTP方法,而不再需要一个一个查看和修改模板文件了。
[b]3、[b]管理数据库升级[/b]
[/b]
开发人员使用关系数据库时,通常需要跟踪和管理数据库结构的升级和变化。当出现以下几种情况时,我们需要使用更成熟的方式跟踪和管理数据库结构的变化:
在团队开发中,每个成员都需要知道数据库结构的任何变化。
当成品部署到服务器上后,需要采用安全稳定的方式去升级数据库结构。
当开发人员在不同的机器上工作时,需要保持数据库同步。
注意:
如果采用JPA进行操作,Hibernate会自动处理数据库结构的升级。如果读者经常需要手动管理数据库结构,并进行一些精细的调整,版本控制就变得必不可少了。
3.1 升级脚本#
Play通过编写升级脚本来跟踪数据库结构的变化。这些脚本采用标准的SQL语句作为语法规则,存放在应用程序的db/evolutions目录下。脚本使用统一的命名规则:编写的第一个脚本命名为1.sql,第二个脚本为2.sql,并以此类推。每个脚本都包含两个部分:Ups部分用于描述需要改变的地方。
Downs部分用于描述如何还原。
以下是数据库升级脚本的例子,起到引导作用:
# Users schema # --- !Ups CREATE TABLE User ( id bigint(20) NOT NULL AUTO_INCREMENT, email varchar(255) NOT NULL, password varchar(255) NOT NULL, fullname varchar(255) NOT NULL, isAdmin boolean NOT NULL, PRIMARY KEY (id) ); # --- !Downs DROP TABLE User;
注意:
在编写数据库升级脚本时,须使用注释明确地将Ups和Downs部分区分开。
如果读者已经在application.conf文件中配置了数据库,并且编写了数据库升级脚本(放置在db/evolutions目录下),应用在启动时就会自动激活数据库的升级模式。我们也可以强制将其关闭,只需在application.conf文件中进行如下配置:
evolutions.enabled=false
一旦数据库的升级模式被激活,框架会执行升级管理。当应用处于DEV模式,Play会在请求到达时检查数据库的结构,如果数据库结构不是最新的,将显示错误页面,并建议使用合适的SQL脚本同步数据库,如图1所示。如果应用处于PROD模式,Play则会在整个应用启动之前进行检查。
![](http://www.playframework.cn/attach/%E7%AE%A1%E7%90%86%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8D%87%E7%BA%A7/evolutions.png)
(图1 数据库结构不同步)
在页面上点击Apply evolutions按钮,就可以直接执行SQL升级脚本。
补充:
如果应用使用内存数据库(db=mem),Play会预先对数据库进行检测。如果数据库为空就会自动执行所有的升级脚本。
3.2 同步#
协作开发中,保持应用同步非常重要。设想一下,如果有两个开发者合力开发项目,开发者A因为自己负责的功能模块需要,创建了新的数据表并编写了升级脚本2.sql:# Add Post # --- !Ups CREATE TABLE Post ( id bigint(20) NOT NULL AUTO_INCREMENT, title varchar(255) NOT NULL, content text NOT NULL, postedAt date NOT NULL, author_id bigint(20) NOT NULL, FOREIGN KEY (author_id) REFERENCES User(id), PRIMARY KEY (id) ); # --- !Downs DROP TABLE Post;
Play会将该升级脚本应用于开发者A的数据库。与此同时,开发者B因功能需求修改了User表,也编写了升级脚本,同样命名为2.sql:
# Update User # --- !Ups ALTER TABLE User ADD age INT; # --- !Downs ALTER TABLE User DROP age;
开发者B先完成了负责的功能模块,并提交了代码(比如开发者采用Git进行管理)。开发者A需要先整合两个人前半段的工作结果,才能开展后续工作,但是在执行git pull的时候,合并会出现如下冲突:
Auto-merging db/evolutions/2.sql CONFLICT (add/add): Merge conflict in db/evolutions/2.sql Automatic merge failed; fix conflicts and then commit the result.
这是因为开发者A和开发者B都创建了2.sql升级脚本,必须进行整合:
<<<<<<< HEAD
# Add Post # --- !Ups CREATE TABLE Post ( id bigint(20) NOT NULL AUTO_INCREMENT, title varchar(255) NOT NULL, content text NOT NULL, postedAt date NOT NULL, author_id bigint(20) NOT NULL, FOREIGN KEY (author_id) REFERENCES User(id), PRIMARY KEY (id) ); # --- !Downs DROP TABLE Post;
=======
# Update User # --- !Ups ALTER TABLE User ADD age INT; # --- !Downs ALTER TABLE User DROP age;
>>>>>>> devB
整合工作非常简单,只需要将冲突的部分合并即可:
# Add Post and update User # --- !Ups ALTER TABLE User ADD age INT; CREATE TABLE Post ( id bigint(20) NOT NULL AUTO_INCREMENT, title varchar(255) NOT NULL, content text NOT NULL, postedAt date NOT NULL, author_id bigint(20) NOT NULL, FOREIGN KEY (author_id) REFERENCES User(id), PRIMARY KEY (id) ); # --- !Downs ALTER TABLE User DROP age; DROP TABLE Post;
将整合后的脚本命名为2.sql,作为升级脚本的最新修订版(注意:与前期开发者A应用到数据库的2.sql不同)。Play会发现这个情况,并询问开发者A是否同步数据库,将最新的修订版2.sql替换原来的版本,如图2所示。
![](http://www.playframework.cn/attach/%E7%AE%A1%E7%90%86%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8D%87%E7%BA%A7/evolutions-conflict.png)
(图2 同步升级脚本)
3.3 非同步状态#
如果脚本(比如3.sql)中存在错误,数据库升级工作将无法完成。当出现这种情况时,Play会将数据库的结构标记为非同步状态,并要求我们手动解决这个问题,之后才能继续别的操作。下例的Ups部分存在错误:# Add another column to User # --- !Ups ALTER TABLE Userxxx ADD company varchar(255); # --- !Downs ALTER TABLE User DROP company;
该脚本在执行时会出现错误,Play将数据库的结构标记为非同步状态,如图3所示:
![](http://www.playframework.cn/attach/%E7%AE%A1%E7%90%86%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8D%87%E7%BA%A7/evolutions-inconsistent.png)
(图3非同步状态)
错误必须得到修正后,才能进行后续操作。使用SQL命令手动更改数据库结构:
ALTER TABLE User ADD company varchar(255);
然后点击Mark it resolved按钮,通知框架问题已经解决。由于原先的升级脚本存在错误,必须将其修正。修改3.sql脚本文件:
# Add another column to User # --- !Ups ALTER TABLE User ADD company varchar(255); # --- !Downs ALTER TABLE User DROP company;
Play会发现该升级脚本是最新的,因此覆盖原有的3.sql执行,如图4所示:
![](http://www.playframework.cn/attach/%E7%AE%A1%E7%90%86%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8D%87%E7%BA%A7/evolutions-resolve.png)
(图4 成功执行数据库结构同步)
图4 所显示的是脚本正确执行的结果,之后可以继续别的工作。
补充:
介绍一个开发小技巧:开发人员可以在每次开发前手动删除原有的数据库,当应用启动时框架就会自动加载所有的升级脚本。这样做的好处是可以使开发人员的数据库一直保持最新版本。
3.4 升级命令#
当应用处于DEV模式时,数据库升级是交互式地进行的。但是在PROD模式下,必须先使用play evolutions命令将数据库结构升级为最新版本,才可以开启应用。当框架发现应用程序的数据库不是最新版本时,控制台会出现如下错误信息:~ _ _ ~ _ __ | | __ _ _ _| | ~ | '_ \| |/ _' | || |_| ~ | __/|_|\____|\__ (_) ~ |_| |__/ ~ ~ play! master-localbuild, http://www.playframework.org ~ framework ID is prod ~ ~ Ctrl+C to stop ~ 13:33:22 INFO ~ Starting ~/test 13:33:22 INFO ~ Precompiling ... 13:33:24 INFO ~ Connected to jdbc:mysql://localhost 13:33:24 WARN ~ 13:33:24 WARN ~ Your database is not up to date. 13:33:24 WARN ~ Use `play evolutions` command to manage database evolutions. 13:33:24 ERROR ~ @662c6n234 Can't start in PROD mode with errors Your database needs evolution! An SQL script will be run on your database. play.db.Evolutions$InvalidDatabaseRevision at play.db.Evolutions.checkEvolutionsState(Evolutions.java:323) at play.db.Evolutions.onApplicationStart(Evolutions.java:197) at play.Play.start(Play.java:452) at play.Play.init(Play.java:298) at play.server.Server.main(Server.java:141) Exception in thread "main" play.db.Evolutions$InvalidDatabaseRevision at play.db.Evolutions.checkEvolutionsState(Evolutions.java:323) at play.db.Evolutions.onApplicationStart(Evolutions.java:197) at play.Play.start(Play.java:452) at play.Play.init(Play.java:298) at play.server.Server.main(Server.java:141)
该错误信息提示我们运行play evolutions命令同步数据库:
$ play evolutions ~ _ _ ~ _ __ | | __ _ _ _| | ~ | '_ \| |/ _' | || |_| ~ | __/|_|\____|\__ (_) ~ |_| |__/ ~ ~ play! master-localbuild, http://www.playframework.org ~ framework ID is gbo ~ ~ Connected to jdbc:mysql://localhost ~ Application revision is 3 [15ed3f5] and Database revision is 0 [da39a3e] ~ ~ Your database needs evolutions! # ---------------------------------------------------------------------------- # --- Rev:1,Ups - 6b21167 CREATE TABLE User ( id bigint(20) NOT NULL AUTO_INCREMENT, email varchar(255) NOT NULL, password varchar(255) NOT NULL, fullname varchar(255) NOT NULL, isAdmin boolean NOT NULL, PRIMARY KEY (id) ); # --- Rev:2,Ups - 9cf7e12 ALTER TABLE User ADD age INT; CREATE TABLE Post ( id bigint(20) NOT NULL AUTO_INCREMENT, title varchar(255) NOT NULL, content text NOT NULL, postedAt date NOT NULL, author_id bigint(20) NOT NULL, FOREIGN KEY (author_id) REFERENCES User(id), PRIMARY KEY (id) ); # --- Rev:3,Ups - 15ed3f5 ALTER TABLE User ADD company varchar(255); # ---------------------------------------------------------------------------- ~ Run `play evolutions:apply` to automatically apply this script to the db ~ or apply it yourself and mark it done using `play evolutions:markApplied` ~
使用play evolutions:apply命令可以通知Play自动执行数据库升级脚本:
play evolutions:apply
如果在成品数据库上手动执行脚本,可以使用play evolutions:markApplied命令通知Play该数据库已经是最新版本了:
play evolutions:markApplied
当应用处于DEV模式,如果框架自动执行升级脚本失败,就需要手动解决,并将数据库结构标记为已修正的:
play evolutions:resolve
相关文章推荐
- play框架使用起来(5)
- play框架使用起来(6)
- play框架使用起来(11)
- play框架使用起来(16)
- play框架使用起来(12)
- play框架使用起来(10)
- play框架使用起来(17)
- play框架使用起来(15)
- play框架使用起来(7)
- play框架使用起来(14)-高级指南
- play框架使用起来(8)
- play框架使用起来(13)
- play使用起来(4)
- Web自动化框架LazyUI使用手册(2)--先跑起来再说(第一个测试用例-百度搜索)
- play 1.x框架的配置与使用
- play框架用起来(3)
- Play 框架学习 (一) 什么是框架 为什么使用框架
- play! 框架的搭建与基本使用方法
- Yii框架官方指南系列18——使用表单:创建动作
- Play框架的验证码使用