Play framework 要点(NEW)
?
其一,通过 Play 框架提供的命令行工具,可以快速创建Java Web 应用
其二,它拥有Java 代码动态编译机制,在修改代码之后,不需要重启服务器就可以直接看到修改之后的结果。
其三,它还使用 JPA 规范来完成领域对象的持久化,可以很方便的使用不同的关系数据库作为后台存储。
其四,它使用 Groovy 作为视图层模板使用的表达式语言。模板之间的继承机制避免了重复的代码。
??? 使用thymeleaf作为模板引擎,就不能再使用Groovy的模板了!
??? 另外学习thymeleaf模板提供的标签和功能。
====================================================================================
play内部使用netty作为服务器?
??? play start 后台模式启动?? play run? 当前窗口运行,关闭窗口,程序也会停止
=================================================================================
指定play 应用的根路径?
http.path=/my
由于company的复数是companies,而play框架原先约定俗成的是在实体类名后直接加字母s,
所以这里使用了注解 @CRUD.For(Company.class),以表明该控制类文件Companies是为company实体类服务的。
@CRUD.For(Company.class)
public class Companies extends CRUD
=================================================================================
Components
??? JBoss Netty for the web server
??? No required ORM, but Ebean (Java) are included for database access
??? Built in hot-reloading
??? sbt for dependency management
The following functionality is present in the core:
??? a clean, RESTful framework
??? CRUD: a module to simplify editing of model objects
??? Secure: a module to enable simple user authentication
??? a validation framework based on annotations
??? a job scheduler
??? a simple to use SMTP mailer
??? JSON and XML parsers and marshallers
??? a persistence layer based on JPA
??? an embedded database for quick deployment/testing purposes
??? a full embedded testing framework
??? an automatic file uploads functionality
??? multi-environment configuration awareness
??? a modular architecture, which enables bringing new features in the core easily
??? OpenID and web services clients
==================================================================================
HTTP stateless translation
Client---[Play--->conf/routes]---Security---Controller
--->
Contoller---[Action(Model:CRUD)]--->render(Args)--->template]---Client
1.Play应用基础配置--->application.conf/db,log
2.路由配置--->routes.conf
3.方法的拦截--->@Before, @After, @Final, @With
4.控制器接收参数--->Controller:Action【in params,get from httprequest, type will be auto transfered】
5.领域对象--->Model:JPA crud
6.返回相应结果--->render()【模板的参数来源:renderArgs;还有隐含对象:session/flash/request/params/out】
??? ????? --->renderJSON(),renderBinary(),renderXml(),renderText()
??? ????? --->redirect(),forbidden(),unauthorized(),notFound(),error(),ok()
6.渲染模板--->template(thymeleaf)/#{}---if/ifnot/elseif/else/list/extends/doLayout/errors/a, @{}, @@{}, ${},th:text(${})
7*.任务调度--->Job:doJob(),doJobWithResult(). @OnApplicationStart @Every(1h)---描述调度策略的 CRON 表达式
8.安全--->Security
9.缓存--->Cache
10.测试--->单元测试play.test.UnitTest(测试模型层代码),功能测试play.test.FunctionalTest(测试控制层代码)
?????? --->yaml格式的测试数据 play.test.Fixtures.laod(),play test http://localhost:9000/@tests
==================================================================================
Play 框架的设计架构就是无状态的,服务端不维护会话状态,由客户端的Cookie完成身份的保持
Flash 作用域和会话Session一样,都通过 cookie 来保存的
Session 作用域保存一些与会话相关的数据,数据在不同请求响应中都有效
Flash 作用域中的数据只在下次请求中是有效的
Application controller support:
??? The controller receives input and initiates a response by making calls on model objects.
Play中数据的有效范围
Scope.RenderArgs? 专门用于为模板渲染时提供需要的数据???
??? The current renderArgs scope: This is a hash map that is accessible during the rendering phase.
??? It means you can access variables stored in this scope during the rendering phase (the template phase).
Scope.Params params?? 获取http请求参数
??? The current HTTP params. This scope allows you to access the HTTP parameters supplied with the request.
??? This is useful for example to know which submit button a user pressed on a form.
Scope.Flash flash? 在第2次请求中有效,以后都无效
??? The current flash scope. The flash is a temporary storage mechanism that is a hash map
??? You can store values associated with keys and later retrieve them.
??? It has one special property: by default, values stored into the flash during the processing of a request will be available during the processing of the immediately following request.
??? Once that second request has been processed, those values are removed automatically from the storage.
Scope.Session session? 整个请求响应周期都有效
??? The current HTTP session. The Play! session is not living on the server side but on the client side.
??? In fact, it is stored in a signed cookie. This session is therefore limited to 4kb.
=================================================================================================================
0.路由匹配
GET???? /?????????????????????????????????????? Application.index
只匹配根路径的请求,http://localhost:9000/ 或者 http://localhost:9000/Blog/ (如果有指定http.path=/Blog)
1.设置内存数据库 db=mem
2.不要提交下面的文件到SVN
When storing a Play application in a VCS, it is important to exclude the tmp/, modules/, lib/, test-result/ and logs/ directories.
If you are using Eclipse, and the play eclipsify command, then you should also exclude .classpath and eclipse/.
3.
@Entity 声明将实体类托管到JPA进行管理
extends Model 目的在于使用Model中写好的并且实用的JAP方法,当然也可以不继承这个Model类,自己使用JPA进行对象操作
@ManyToOne 在多的一端使用
@OneToMany 在一的一端使用,并使用MappedBy="对方中定义的我方对象的引用",cascade级联属性根据实际情况使用
play中对JPA的使用进行了封装,具体参考http://localhost:9000/@documentation/jpa
其它JAP需要学习相关文档,http://docs.oracle.com/javaee/5/tutorial/doc/bnbpz.html
play底层使用Hibernate完成对象持久化,需要进一步学习Hibernate的相关知识。
4.bootstrap
不需要外部http请求来触发,将在约定情况下自动执行
比如,在应用启动的时候就运行一个Job,进行初始化
5.模板复用---重用代码、代码复用性
play使用Groovy模板引擎,具体表达式参考http://localhost:9000/@documentation/templates
6. @Before interceptor
统一模板中有可能使用一些参数变量,因此,通过拦截器对其统一设置。
Play.configuration.getProperty("") 可以获取application.conf中设置的参数值
renderArgs("key","value")设置的参数,在模板渲染阶段使用
使用标签将使得程序非常的简练,避免了大量重复代码的书写,而且很灵活。
根据传入的不同参数,标签中执行不同的代码,动态化。
7.css应用,页面漂亮与否由它决定
8.play路径匹配规则
/client 与 /client/ 的效果是不一样的!!!
除非声明为 /client/? ,则上述两种效果一样
http://localhost:9000/@documentation/routes#syntax
9.label 对目标进行绑定,通过点击文字实现点击目标的效果
10.module
http://localhost:9000/@documentation/crud
11.play将service与dao都放到了model中进行,model通过JPA实现dao层的功能,model中定义的方法作为service层的功能。
12.conf目录下的messages文件中配置的字符映射关系将被自动替换。
13.windows下删除文件和目录
del /S/Q demo? 删除demo目录下的所有文件
rmdir /s/Q demo 删除demo目录
14.play提供Secure模块
首先引入Secure模块,然后,再需要进行登录验证的地方,使用@With(Secure.class)进行标注,在访问该资源(类或者方法)时,就会进行检查
@with(Secure.class),在Controller上声明之后,访问Controller就会调用Secure.check()判断用户是否已经登录
自定义Security类来实现对授权逻辑的控制
步骤:
??? dependencies.yml中加入??? - play -> secure
??? 配置路由??? *?????? /??????? module:secure
??? play dependencies
??? play eclipsify
??? app/controllers 创建Security类,继承Secure.Security,重写authenticate(String username, String password),在这个方法中进行是否授权的控制
15.flash.get("url")获取当前请求的url
16.什么是JPDA
Java Platform Debugger Architecture(JPDA:Java平台调试架构) 由Java虚拟机后端和调试平台前端组成
17.访问控制流程
不管是否已经登录,每次访问都会执行checkAccess(),如果!session.contains("username"),直接返回到登录页面
check()使用了拦截器,@Before(unless={"login", "authenticate", "logout"}),并指定了对哪些方法不进行拦截
登录,登出,校验用户名密码这3个方法不拦截!
登录前访问页面:
checkAccess() 总的入口 --->if(!session.contains("username")) 如果没有登录,则进入login()
---> login()--->Http.Cookie remember = request.cookies.get("rememberme"); 判断是否以前登录过,并且具备下次自动登录的特征
??? ??? ??? ??? ??? if(remember != null)? 如果是,则检查签名,
??? ??? ??? ??? ??? 否则重新登录--->login()
跳转到登录页面:
authenticate(@Required String username, String password, boolean remember)
Security.invoke("authentify", username, password);---> throws UnsupportedOperationException
allowed = (Boolean)Security.invoke("authenticate", username, password);将调用我们自己写的authenticate()---多态
if(validation.hasErrors() || !allowed) --->login(); 如果allow=false,即我们自己写的authenticate()返回了false,则执行login()
如果我们自己写的authenticate()返回了true,则继续执行:
session.put("username", username);
redirectToOriginalURL()---> String url = flash.get("url") --->redirect(url);
18.往session中存数据,即往浏览器cookie中存数据
play如何通过session.contains("username")来判断用户是否登录
首先,session与浏览器的cookie相关,session的数据不在server端进行存储
第二,如果登录成功,play会设置username到cookie中,下次浏览器带上cookie去找play,这是就能通过session.contains("username")判断登录状态了
因为,用户登录失败,浏览器的cookie中是不会有username的
此外,为了防止cookie篡改,server端会返回一个经过签名的字符串,和一个用于计算的字符串,play取到之后会在server端对字符串重新签名,看cookie是否被篡改过
大概就是这么个意思了!
由于session的内容与客户端浏览器有关,所以,不同浏览器之间的通过session.contains("username")来判断用户是否登录不会存在混淆!
19.路由斜线问题【下面的路由配置顺序不能换!具体的写在上面,上面的优先匹配,没有匹配时才与下面的进行匹配】
GET???? /admin/???????????????????????????????? Admin.index
*?????? /admin????????????????????????????????? module:crud
http://localhost:9000/admin/ 访问 Admin.index()
http://localhost:9000/admin 访问CRUD.index()
对于application.conf中有关http.path的配置
如,配置http.path=/demo
http://localhost:9000/demo? 主页
http://localhost:9000/demo/ 主页
如,配置http.path=/demo/ 怎么着都访问不了
20、路由灵活配置,访问同样的方法,定制更合适的URI样式
#打开一个已存在的#{form @save(post?.id)},如果post有id值,向浏览器发生html数据时,action被指定为 /admin/myPosts/1
GET???? /admin/myPosts/{id}???????????????????? Admin.form
#新建一个#{form @save(post?.id)},如果post没有id值,向浏览器发生html数据时,action被指定为 /admin/new
GET???? /admin/new????????????????????????????? Admin.form
#编辑一个已存在的,<a href="@{Admin.form(post.id)}">${post.title}</a>,如果post有id值,则路径显示为带id的
POST??? /admin/myPosts/{id}???????????????????? Admin.save
#保存一个新的,<a href="@{Admin.form(post.id)}">${post.title}</a>,如果post没有id值,则路径显示为带id的
POST??? /admin/new????????????????????????????? Admin.save