玩转play framework ( by quqi99 )

本文详细介绍Play框架的安装配置过程、基本应用开发步骤及高级功能使用,包括视图、控制层、模型层的实现方法,同时介绍了无状态体系结构、任务调度、支持非Web应用等方面的内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


作者:张华  发表于:2011-04-06
版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明

( http://blog.youkuaiyun.com/quqi99 )

p { margin-bottom: 0.21cm; }h1 { margin-bottom: 0.21cm; }h1.western { font-family: "Arial",sans-serif; font-size: 16pt; }h1.cjk { font-family: "宋体"; font-size: 16pt; font-style: normal; font-weight: bold; }h1.ctl { font-family: "Tahoma"; font-size: 16pt; font-weight: bold; }h2 { margin-bottom: 0.21cm; }h2.western { font-family: "Arial",sans-serif; font-size: 14pt; font-style: italic; }h2.cjk { font-family: "宋体"; font-size: 14pt; font-style: italic; }h2.ctl { font-family: "Tahoma"; font-size: 14pt; font-style: italic; }pre { font-family: "Courier New",monospace; }h3 { margin-bottom: 0.21cm; }h3.western { font-family: "Arial",sans-serif; }h3.cjk { font-family: "宋体"; font-style: normal; }h3.ctl { font-family: "Tahoma"; }a:link { color: rgb(0, 0, 255); }

 



内容目录

1开发环境构建 1

1.1下载二进制发布包 1

1.2创建应用 1

1.3集成eclipse 2

2Hello World 2

3Play程序开发 3

3.1视图层 3

3.1.1模板元素 3

3.1.2模板继承 3

3.2控制层 3

3.3模型层 4

3.4无状态的体系结构 4

3.5任务调度 5

3.6支持non-web应用 5

3.7支持CRUD应用 8

3.8支持安全 9


 

1开发环境构建

1.1下载二进制发布包

http://download.playframework.org/releases/play-1.2.1.zip

下载完后解压,例如我解压的目录是:/home/workspace/play-1.2.1

1.2创建应用

zhanghua:play-1.2.1root# ./play new QATool

~ _ _

~ _ __ | | __ _ _ _| |

~| '_ /| |/ _' | || |_|

~| __/|_|/____|/__ (_)

~|_| |__/

~

~play! 1.2.1, http://www.playframework.org

~

~The new application will be created in/home/workspace/play-1.2.1/QATool

~What is the application name? [QATool]

~

~OK, the application is created.

~Start it with : play run QATool

~Have fun!

~

zhanghua:play-1.2.1root# ./play run QATool

~ _ _

~ _ __ | | __ _ _ _| |

~| '_ /| |/ _' | || |_|

~| __/|_|/____|/__ (_)

~|_| |__/

~

~play! 1.2.1, http://www.playframework.org

~

~Ctrl+C to stop

~

Listeningfor transport dt_socket at address: 8000

10:44:48,951INFO ~ Starting /home/workspace/play-1.2.1/QATool

10:44:49,774WARN ~ You're running Play! in DEV mode

10:44:49,876INFO ~ Listening for HTTP on port 9000 (Waiting a first request tostart) ...

 

这时,你能在浏览器上访问http://localhost:9000验证

1.3集成eclipse

zhanghua:play-1.2.1root# ./play eclipsify QATool

 

然后,能过File/Import/General/Existingproject… QATool应用导入到eclipse中。

其次,要安装Eclipse插件,在support/eclipse/目录下,要安装它,只需将你在该目录下找到的JAR文件,简单地复制到Eclipse安装目录的dropins文件夹下。

说明一下,eclipsify命令生成若干个应用程序的启动器(launcher),主启动器(mainlauncher)只能通过EclipseRunAs 命令使用。可以随时通过DebugAs 启动一个调试会话,然后使用ConnectJPDA launcher ,停止调试会话并不会导致服务器终止。如果你对应用程序做了任何重要的修改,如改变classpath,则需要使用eclipsify重新生成Eclipse配置文件。

在调试时,首先用./playrun QATool 命令启动应用;然后连接JPDA调试器即可。

在启动应用时,也可以先将所有conf目录、应用本身的JAR包、及play本身的JAR包加到环境变量后再执行下列命令即可(通过runas启动,而不是debugas)

java-Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n

-Dapplication.path="${project_loc:QATool}"

-javaagent:"/home/workspace/play-1.2.1/framework/play-1.2.1.jar"

play.server.Server

2Hello World

  1. vimapp/views/Application/index.html

#{extends'main.html' /}

#{settitle:'Home' /}

 

#{ifflash.error}

<pstyle="color:#c00">

${flash.error}

</p>

#{/if}

<formaction="@{Application.sayHello()}"method="GET">

<inputtype="text"name="myName"/>

<inputtype="submit"value="Sayhello!" />

</form>

 

2vim app/controllers/Application.java 添加一方法:

 

publicstaticvoidsayHello(@RequiredStringmyName) {

if(validation.hasErrors()){

flash.error("Oops,please enter your name!");

index();

}

render(myName);

}

 

3vimapp/views/Application/sayHello.html

#{extends'main.html' /}

       #{set title:'Home' /}


 

       <h1>Hello ${myName ?: 'guest'}!</h1>


 

       <a href="@{Application.index()}">Back to form</a>

3Play程序开发

3.1视图层

3.1.1模板元素

Play框架的模板技术使用的是Groovy语言。在模板中可以使用的动态元素如下说明:

${...} 用来对一个表达式求值,如${note.title}是指取note对象的title属性。

@{...}@@{...}是指JAVA端控制器动作方法的相对URL及绝对URL

&{...}用来显示经国际化之后的消息内容。

*{...}*注释

%{...}%用来添加复杂的Groovy脚本,可以声明变量和添加语句。

#{...} 用来调用Play框架或自定义的标签。


举个例子,如对topics变量进行循环迭代,则用Groovy模板,如下:

%{for(topic in topics){ }%

<td>${topic.id}</td>

%{} }%

3.1.2模板继承

Play框架中可以使用#{extends}#{doLayout}来实现模板之间的继承。

在父模板中可以包含任意的内容。在需要由子模板填充的位置,使用#{doLayout/}进行声明即可。在子模板中通过#{extends}来声明所继承的模板。如#{extends'main.html'}就声明继承自模板main.html。当子模板被生成之后,将包含父模板中的内容。而子模板中只需要定义扩展的内容即可。

3.2控制层

在控制层的动作方法完成了与业务逻辑相关的处理之后,需要把响应返回给客户端。响应的结果可能是正确完成,也可能是出现错误。Play框架提供了方便的实现用来返回不同类型的响应。使用play.mvc.Controller类提供的不同方法就可以生成这些响应内容。

  • 请求正确完成,HTTP状态代码为200。使用ok()方法生成不带内容的响应。使用render()方法来生成使用模板的响应。使用renderText()方法生成text/plain类型的纯文本响应。使用renderXml()方法生成text/xml类型的 XML格式的响应。使用renderJSON()方法生成application/json类型的 JSON格式的响应。使用renderBinary()方法生成二进制内容的响应。

  • 跳转到新的页面,HTTP状态代码为3XX。使用redirect()方法来跳转到新的URL。使用notModified()方法来返回状态代码304

  • HTTP状态代码4XX。使用unauthorized()方法返回状态代码401。使用forbidden()方法返回状态代码403。使用notFound()方法返回状态代码404

  • 服务器内部错误,HTTP状态代码5XX。使用error()方法返回状态代码500


3.3模型层

领域对象的实例一般需要持久化下来。最常见的持久化方式就是使用关系数据库。Play框架使用JPA规范来进行领域对象的持久化。具体的后台实现使用的是Hibernate。开发人员只需要使用JPA规范定义的标注,就可以声明领域的持久化行为。比较好的做法是将领域对象类继承自Play框架提供的play.db.jpa.Model类。play.db.jpa.Model类提供了一个域id作为对象的标识符,也是对应的数据库表中的主键。play.db.jpa.JPASupport类是play.db.jpa.Model的父类,提供了一些实用方法用来完成从领域对象到数据库之间的映射。

举些例子:

1)分页查询:

List<Content>list = Content.find("status=? order by id asc",status).from(startPos).fetch(pageSize);

2)查询数目

Content.count("status= ?",status);

3)保存user.save();

4)更新

Useruser = Dao.findByUsername("quqi99");

user.setPassword("111111");

user.save();

 

可参考:
Play!
连接
MySQL
配置



 
http://c4fun.iteye.com/blog/506959



 

http://www.playframework.org/documentation/1.1.1/jpa



 

3.4无状态的体系结构

HTTP协议本身就被设计成无状态的,采用请求/响应的模式。不同的请求之间并不存在相互关系。但是这种架构模式在开发某些Web应用的时候不是很方便。有些应用要求用户进行认证登录之后才能进行某些操作。同样的URL,认证和未认证用户看到的内容是不同的。而且用户认证成功之后,他应该在一段时间内保持这种认证状态。否则的话,用户每次都需要输入用户名和密码才能访问受限的内容。对于这种情况,很多 Web开发框架提供了会话的支持,允许应用保存一些与会话相关的数据。JavaServlet 规范中的javax.servlet.http.HttpSession 就是一种会话的接口。应用的服务器会负责维护每个会话相关的数据。这些数据可以通过一个会话ID来进行标识。这个标识会利用浏览器的cookie机制保存在浏览器端,也可以作为请求URL的参数来传递。服务器端通过此标识来识别每个会话。在处理相应的请求的时候,就可以根据会话ID来获取保存在服务器端上的会话数据。会话机制的问题是会影响应用的可伸缩性。如果一个应用使用多台服务器的话,就需要额外的机制来保证同一用户在不同机器上面的会话是同步的。而无状态的实现则不存在这个问题,对于某一个请求,由不同机器来处理的结果都是相同的。

Play框架的设计架构就是无状态的。它没有提供服务器端的机制用来维护跨多个请求的数据。如果确实需要保存这样的数据的话,可以考虑下面几种方案:

  • 保存在SessionFlash作用域中。Play框架中仍然有会话的机制,但是并没有提供在服务器端保存会话数据的能力。会话数据是保存在浏览器的cookie中的,由浏览器在每次请求的时候自动发送。通过这种方式来达到维护会话数据的目的。由于会话数据是保存在cookie中,其大小是有限制的,一般不能超过4K字节,而且只能保存字符串类型的数据。Flash作用域和会话一样,也是通过cookie来保存的。所不同的是,Flash作用域中的数据只在下次请求中是有效的。

  • 保存在持久化的数据存储中,如数据库中。如果需要在多个请求中使用同一个领域对象的话,可以把这个对象的ID保存在 SessionFlash作用域中,而在控制器动作方法中使用此ID来从数据库中查询相应的对象。

  • 保存在暂时性数据存储中,如缓存中。Play框架内置了缓存的支持,通过调用类play.cache.Cache就可以对缓存进行操作。与使用持久化存储类似,缓存中的键的值可以保存在SessionFlash作用域中。

对于熟悉了 JavaServlet 规范的开发人员来说,需要一些时间来适应Play框架的这种无状态的体系结构。不过这种结构对于应用的可伸缩性来说,确实是非常有好处的。

3.5任务调度

Web应用开发中,有时候会需要定期执行一些调度任务,比如数据库备份和数据同步等。这些任务不是通过HTTP请求来触发的,而是定时执行的。Play框架提供了内置的任务调度支持的能力。创建新任务的时候,只需要继承自play.jobs.Job类,并覆写doJob()方法即可。如果要创建的任务有返回结果的话,覆写doJobWithResult()方法即可。任务创建完成之后,可以选择不同的调度方式。一种方式是在应用启动的时候执行一次。只需要在任务的Java类上添加标注@OnApplicationStart即可。对于定期执行的任务,Play框架提供了两个标注:一个是@Every,用来按照固定的时间间隔调度任务,如@Every("1h")声明任务每个小时执行一次;另外一个是@On,用来声明描述调度策略的CRON表达式。

3.6支持non-web应用

对于non-web应用,如果想要重要模型层的话,可用如下代码:

packagenonwebapp;

 

importjava.io.File;

importjava.lang.reflect.Method;

importjava.util.List;

 

importmodels.Content;

importplay.Play;

importplay.db.DBPlugin;

importplay.db.jpa.JPAPlugin;

importplay.test.Fixtures;

 

/**

*

*author: huazhangsince : 2011-6-21

*/

publicabstractclassPlayLoaderMain

{

 

publicstaticvoidmain(String[] args) throwsException

{

try

{

StringappPath = "/home/workspace/play-1.2.1/QATool";

Fileroot = newFile(appPath);

Play.init(root,System.getProperty("play.id",""));

 

Thread.currentThread().setContextClassLoader(Play.classloader);

Class<?>c= Play.classloader.loadClass("nonwebapp.BuildAccounts");

Methodm = c.getMethod("run");

m.invoke(c.newInstance());

}catch(Exception e)

{

e.printStackTrace();

}

}

 

publicvoidrun() throwsException

{

newDBPlugin().onApplicationStart();

newJPAPlugin().onApplicationStart();

JPAPlugin.startTx(true);

 

exec();

 

JPAPlugin.closeTx(false);

}

 

publicabstractvoidexec() throwsException;

}



packagenonwebapp;

 

importjava.util.List;

 

importmodels.Content;

 

/**

*

*author: huazhangsince : 2011-6-22

*/

publicclassBuildAccounts extendsPlayLoaderMain

{

@Override

publicvoidexec() throwsException

{

List<Content>list= Content.findAll();

System.out.println("");

}

}

 

再写个脚本调用它,脚本中加环境变量

 

#!/bin/bash

#huazhang

#2011-06-28

#

 

#resolve links - $0 may be a softlink

THIS="$0"

while[ -h "$THIS" ]; do

ls=`ls-ld"$THIS"`

link=`expr"$ls": '.*-> /(.*/)$'`

ifexpr"$link" : '.*/.*' > /dev/null;then

THIS="$link"

else

THIS=`dirname"$THIS"`/"$link"

fi

done

 

#some directories

THIS_DIR=`dirname"$THIS"`

QATOOL_HOME=`cd"$THIS_DIR" ; pwd`

PLAY_HOME=`cd"$QATOOL_HOME/.." ; pwd`

 

if[ $# -lt1 ] ; then

echo"USAGE: $0 class"

echo" e.g.: $0 nonwebapp.ImportData"

exit1;

fi

 

if[ "$JAVA_HOME" = "" ]; then

echo"Error: JAVA_HOME is not set."

exit1

fi

 

JAVA=$JAVA_HOME/bin/java

JAVA_HEAP_MAX=-Xmx1000m

 

forf in ${PLAY_HOME}/framework/*.jar; do

CLASSPATH=${CLASSPATH}:$f;

done

forf in ${PLAY_HOME}/framework/lib/*.jar;do

CLASSPATH=${CLASSPATH}:$f;

done

 

if[ -d "${QATOOL_HOME}/conf"]; then

CLASSPATH=${CLASSPATH}:${QATOOL_HOME}/conf

fi

forf in $QATOOL_HOME/lib/*.jar;do

CLASSPATH=${CLASSPATH}:$f;

done

if[ -d "${QATOOL_HOME}/tmp/classes"]; then

CLASSPATH=${CLASSPATH}:${QATOOL_HOME}/tmp/classes

fi

 

#default log directory & file

if[ "$QATOOL_LOGFILE" = "" ]; then

QATOOL_LOGFILE="$QATOOL_HOME/logs/QATool.log"

fi

 

if[ "x$JAVA_LIBRARY_PATH" != "x" ]; then

QATOOL_OPTS="$QATOOL_OPTS-Djava.library.path=$JAVA_LIBRARY_PATH"

fi

 

#run it

JAVA_OPTS="-server-Xms1600m -Xmx1600m -XX:PermSize=64M -XX:MaxNewSize=256m-XX:MaxPermSize=128m -Djava.awt.headless=true"

exec"$JAVA" $QATOOL_OPTS -classpath"$CLASSPATH" "$@"

3.7支持CRUD应用

1)vim application.conf

#Import the crud module

module.crud=${play.path}/modules/crud

2) vim routes

#Import CRUD routes

* /admin module:crud

3)改动了配置,要重新运行下列命令:

zhanghua:play-1.2.1root# ./play eclipsify QATool

4)新建Control

packagecontrollers;

/**

*

*author: huazhang

*since : 2011-6-27

*/

publicclassUsers extendsCRUD

{

}

5)新建Model

/**

*

*author: huazhang

*since : 2011-6-27

*/

@Entity

publicclassUser extendsModel

{

@Email

@Required

@MaxSize(256)

publicString username;

@Required

publicString password;

@Required

publicString role;

  1. 启动后访问http://localhost:9000/admin即可

7)客户化字符串,vim conf/messages, 添加:

username=用户名

password=密码

role=角色

8)客户化表现层,执行下列命令创建/app/views/Users/list.html

zhanghua:play-1.2.1root# ./play crud:ov --template Users/list

3.8支持安全

http://www.playframework.org/documentation/1.0/secure

1)vim application.conf

#Import the securemodule

module.secure=${play.path}/modules/secure

2) vim routes

#Import Secure routes

     *      /                module:secure

3)改动了配置,要重新运行下列命令:

zhanghua:play-1.2.1root# ./play eclipsify QATool

4)修改Controller,添加WithCheck两个标签:

@With(Secure.class)

publicclassApplication extendsController {

 

@Check(Constant.ROLE_ADMIN)

publicstaticvoidindex() {

Stringuser= Security.connected();

System.out.println("");

render();

}

5)新建一个自定义Security类,如下:

/**

*

*author: huazhang

*since : 2011-6-28

*/

publicclassSecurity extendsSecure.Security

{

staticbooleanauthentify(String username, String password)

{

Useruser = Dao.findByUsername(username);

returnuser != null&& user.password.equals(password);

}

staticbooleancheck(String role) {

StringloginUser = connected();

Useruser = Dao.findByUsername(loginUser);

returnuser==null? false: role.equalsIgnoreCase(user.getRole());

}

}

内容概要:本文档为《400_IB Specification Vol 2-Release-2.0-Final-2025-07-31.pdf》,主要描述了InfiniBand架构2.0版本的物理层规范。文档详细规定了链路初始化、配置与训练流程,包括但不限于传输序列(TS1、TS2、TS3)、链路去偏斜、波特率、前向纠错(FEC)支持、链路速度协商及扩展速度选项等。此外,还介绍了链路状态机的不同状态(如禁用、轮询、配置等),以及各状态下应遵循的规则和命令。针对不同数据速率(从SDR到XDR)的链路格式化规则也有详细说明,确保数据包格式和控制符号在多条物理通道上的一致性和正确性。文档还涵盖了链路性能监控和错误检测机制。 适用人群:适用于从事网络硬件设计、开发及维护的技术人员,尤其是那些需要深入了解InfiniBand物理层细节的专业人士。 使用场景及目标:① 设计和实现支持多种数据速率和编码方式的InfiniBand设备;② 开发链路初始化和训练算法,确保链路两端设备能够正确配置并优化通信质量;③ 实现链路性能监控和错误检测,提高系统的可靠性和稳定性。 其他说明:本文档属于InfiniBand贸易协会所有,为专有信息,仅供内部参考和技术交流使用。文档内容详尽,对于理解和实施InfiniBand接口具有重要指导意义。读者应结合相关背景资料进行学习,以确保正确理解和应用规范中的各项技术要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值