本篇希望在大家看过之后,能让大家对play的全貌有一个清晰的认识,如果感兴趣的话再去探究详细的操作步骤。无论是对于play的新手还是play的已经使用者,相信都会带来不同的收获,下面开始吧!
前置知识:一点Groovy、一些JPA
一、play简介
play是国外的一家技术公司lightbend开发的一栈式web开发框架,同时支持java和scala两门语言。他通过高性能的底层技术,集成了Javaweb应用开发所需要的几乎所有的组件和API,并做了简单的封装,使得开发更加快速简洁,同时也提高了性能。正如他设计之初的目标一样——简化web开发工作,提高开发效率。
1、play的优点
1)开发效率高
自带热加载功能:
因为基于Eclipse编译器实现了即时编译(JIT),省去了重启项目的时间。
大量封装和各种库:
play在各个环节都做了封装和简化,并提供了多种功能开箱即用的类库,这一点下面会介绍。
强大的领域驱动模型层:
play采用JPA做持久化框架,崇尚马丁。福乐提出的“充血模型”(就是主张实体类之间应该高内聚低耦合,将当前实体类相关的数据和行为全放在当前实体类中)。为了完成这一点,play提供了公共的实体类父类,继承该父类,即可拥有额外的属性和功能(比如实体类的CRUD操作)。
自带高效的模板引擎
模板引擎的动态部分采用Groovy语法,不过很简单,就是基本的if-else、for循环、插值表达式、url表达式等基本的模板引擎功能。
没有编译和打包的过程
一般情况下,部署play项目时不需要手动编译和打包,直接copy源码文件夹,通过play的命令启动即可。play不讲究框架的分层处理,所以service层和DAO层显得不是很重要。
2)遵循服务端无状态的设计,便于水平扩展
3)设计思想值得借鉴
2、play的缺点
1)1版本没有较好的依赖控制工具,还是采用jar包放在类路径的方式,但是影响不大
2)数据层不够强大
3、play与spring的对比
相同点:
处理http请求的方式是一样的。
不同点:
1)play是一栈式web开发框架,可以说是五脏俱全;spring更多的是资源整合框架。
2)play不是基于servlet的,所以不具备servlet标准的servlet、filter、listener、session等api,但是有替代方案。
3)play不具备spring的IOC、AOP功能,使用别的类的方法需要new对象或者设计成static的
4)play一般不需要编译、打包等项目管理过程。
5)play通过提供的脚本命令来执行操作,例如创建项目、模块,运行,停止,测试,生成环境id等,具体可通过play help 查看所有命令及用法。而spring一般需要打包并放到web容器中运行,虽然都可以使用内嵌的容器。
4、play画像或参照物:
SpringBoot+JPA+thymeleaf+UI框架+jquery这套组合,外加ActiveRecord模式、JRebel工具、很多功能类库、某个内置的高性能服务器、命令行解释器。
OK,相信看完以上简介后,你能对play有一个大体的认识。下面将展开来讲,看下play具体提供了哪些功能。
二、play的安装与项目初始化
1、下载和安装
GitHub - playframework/play1: Play frameworkz 这里有play在github上的源码。
你可以从该项目的tags中找play的历史版本,比如该文章用的play1.5.1版本 Tags · playframework/play1 · GitHub
windows下开发,下载.zip包。之后解压到一个无空格非中文的路径下即可。
为了方便使用play的命令,最好将play的安装目录配置到windows下的path环境变量中,方便在任何地方使用play的命令。
然后shell中输入play,出现一下界面表示安装成功
play框架也是用java写的,也需要依赖其他类库。这里重点关注两个文件%PLAY_HOME%/framework/play-1.5.1.jar 和%PLAY_HOME%/framework/lib文件夹,一个是play框架的核心源码,另一个是play所依赖的jar包。
2、初始化
在想要创建play项目的地方输入play的命令来创建和运行项目,如下:
// 创建并初始化一个play项目
play new appName
// 运行该项目
play run appName
就像创建Maven或springBoot项目一下,使用play new 可以快速生成标准化的play项目,具体生成的文件夹的作用,可以参考官方说明
3、IntelliJ Idea中开发play项目
可以将play项目交给idea来托管执行,就能使用idea的功能按钮来运行play项目了,但是需要一些配置,如下
1)先用如下命令生成一个.ipr 环境配置文件,就像.iml文件一样
play idealize appName
之后双击或用idea打开这个文件就能打开play项目了。
2)添加运行配置
- In IntelliJ IDEA, on the Run menu, select Edit Configurations.
- Right-click on Application under Defaults and select Add New Configuration.
- Under Main class, enter
play.server.Server
.- Under VM parameters, enter
-Dapplication.path="."
.- Under Working directory, enter the application path.
- Under Before launch, remove
Make
if exists.
ps:如果想只使用命令的方式启动,也可以不添加以上配置。
OK,介绍也介绍了,安装也安装了,启动也启动了,接下来就看一下如何使用play进行开发吧!
三、使用play快速开发
3.1 play的运行流程
如果你熟悉SpringMVC开发的话,你会发现play的运行流程和SpringMVC是一样的,同样是M(模型)-V(视图)-C(控制)的开发模式,同样可以基于模板进行后端渲染视图,或是返回json数据让前端通过js脚本渲染视图。
3.2 领域模型对象
实体类继承Model类,即可拥有单表的crud功能,也可以用JPA或JPQL功能。
play中约定,所有public的、非static的、非final的变量都是实体类的属性,通过对象.属性的方式编写。在编译后会play自动转换成对应的getter和setter。当然如果用户自定义了getter和setter,play在编译时就会使用用户自定义的了。
3.2.1 DB访问
a、继承Model或GenericModel类
play提供了一组程序让用户对JPA实体的操作更加简便,只需要继承Model类或GenericModel类即可完成CURD操作,还可以使用简化查询(类似springData的自定义方法查询)、JPQL查询。
b、使用JPA的EntityManager
直接通过实体类.em() 或 JPA.em()获取EntityManager,然后就可以使用原生JPA的方式进行操作了
c、原生JDBC操作
play提供了一个DB工具类,能让用户使用原生JDBC的方式操作数据库。直接DB.getConnection() 获取JDBC连接,就能用JDBC的方式操作数据库了。
3.2.2 事务
默认情况下,play对每一个action方法都开启了事务,意味着事务会自动提交和回滚。play提供了两个注解来改变默认的行为:
// 变成只读的事务
@Transactional(readOnly = true)
// 关闭事务
@NoTransaction
// 强制执行事务回滚
JPA.setRollbackOnly();
特别的:play要求所有对对象的更改都要显示调用save()方法进行更新才行。
3.3 Controller 父类
面向http协议,定义了很多Controller层通用的功能方法和对象,所有controller都要继承它。
例如:
3.3.1 参数接收
a、自动解析并映射
和SpringMVC一样,play会自动解析Http请求中的参数,并赋值给controller层方法的入参。
默认会从以下地方解析http请求中的数据,query string、request body、url path(适用于rest风格的url)。
play将尝试转换成action方法入参中声明类型,转化不了就使用默认值,所以action方法的入参可以是 基本数据类型及其包装类、对象(支持嵌套对象的解析)、map、List、Date、File(对于文件上传,play会先存到一个临时目录,并在请求结束时删除该文件)等
特殊的:JPA实体类作为入参,如果提供了实体类的id,play会先查询出来该实体类,再用http中的参数更新该实体类;如果没id就不查询了直接赋值,支持嵌套对象的查询和修改。
b、params 对象
能直接获取http请求中的数据,作用和request.getParameterMap() 一样,但是做了封装,例如params.getBigDecimal("money")
3.3.2 参数验证
play提供了一个Validation类,用于对数据进行验证,并在内部封装了错误信息errors。
提供了三种验证方法:
1)类似断言 :使用Validation.xxx方法直接验证
2)校验注解:将注解直接标记在action方法的入参上即可。
3)类似JSR303的注解的验证方式:实体类的属性上加入校验注解,action方法的参数前标记@valid 注解即可像JSR303一样验证多个参数。
还能自定义错误信息
官网:validation - 1.5.x
3.3.3 临时数据存储
play提供了session和flash域,用于在跨两个或多个http请求中共享数据,全都是采用Cookie机制来回传的数据(因为play想要让服务端无状态,使用cookie可以跨服务器共享数据),因此数据量非常有限。
》》session:并非servlet中的session,准确来说应该叫会话,数据保存在http的cookie中,而不是服务端。能跨多个http共享数据,需要使用play的配置 application.session.maxAge 配置才能实现数据的持久化。
》》flash域:也是用cookie保存的数据,仅在下一个http请求中共享数据。一般用来返回错误信息。
特别的:若想使用Java servlet中的session,可以用play中的Cache来存储数据,然后将唯一key放到会话或者flash中即可。
3.3.4 http响应
Controller父类提供了多种renderxxx()方法,用于返回不同格式的数据,如
renderJson
renderXml
renderText
renderHtml
renderBinary(二进制流,文件下载)
render(渲染html模板,默认的视图解析器规则是views文件夹下面和当前action方法所在的包名-类名-方法名 同名的html文件)
renderTemlate:当然可以指定要渲染的模板。
3.3.5 重定向redirect
play中没有请求的转发,但是支持“曲折的”重定向。很简单只需要一个action方法中调用另一个action方法即可。但是play规定一个http请求只能调用一个action方法,所以当想要调用另一个action方法进行重定向时,play其实先返回一个302响应,然后要求浏览器再次发送要重定向的请求,并不是在服务端直接重定向的。
3.3.6 http请求拦截
play提供了@Before(方法之前被调用)、@After(方法正确返回之后被调用)、@Catch(方法抛出异常后被调用)、@Finally(方法执行结束后调用,无论成功还是失败),将这几个注解标记在某个action方法上,就能对该action方法所在controller以及后代controller中所有的action方法生效。这几个注解可以完成AOP和全局异常处理器或拦截器的功能。
@with注解:该注解标记在一个类上,可以让该类额外继承目标类,实现java多继承的特点,定义拦截器等时可以使用上这个注解。
参考: controllers - 1.5.x
3.4、模板语法
play的模板引擎基于基本的Groovy语法,不过很简单,和JSP大同小异,所以可在模板中使用java代码。关于UI框架,play没做要求,想Bootstrap、layUI都可以,但是不知道像elementUI、antDesign这样的行不行,有没有老铁在评论区给解答一下?
不得不承认,小项目采用前后端不分离的开发模式,确实比前后端分离采用JS渲染DOM的方式,在开发速度上确实快很多。虽然后来前后端分离后,前端的JS框架也使用了模板引擎,JS框架负责从后端API接收数据和渲染模板,但也只是加快了前端的开发速度,对于整个项目的开发速度还是不如前后端不分离时,后端渲染模板来的快。
参照官网: templates - 1.5.x
3.5 异步作业
play提供了一个Job类,用来执行异步任务。继承Job类并重写他的doJob()、doJobWithResult()即可创建一个任务。
基于创建的任务,我们有三种方式来使用他:
1)引导任务(Bootstrap task)
只需要在任务类上添加 @OnApplicationStart (在应用启动时执行)或者 @OnApplicationStop(在应用关闭时执行) 即可
2)定时调度任务(Scheduled task)
在任务类上添加 @Every("间隔时间") 间隔时间的单位可以有如1h、10mn、30s
或者使用@on("cron表达式6位") 注解使用cron表达式来完成
3)手动触发异步任务
通过某个任务对象的now方法(立即执行)、in方法(延迟执行)、afterRequest方法(http响应之后执行) 手动触发自定义的任务。
3.6 单元测试
play中测试只能在测试模式中进行,通过play test 启动测试模式。
步骤:
1)编写自己的单元测试类继承UnitTest或FunctionalTest,
2)编写单元测试方法
3)通过ip:port/@tests访问测试界面,点击需要测试的方法即可
3.7 辅助工具
3.7.1 缓存
缓存是高性能应用必备的组件。play提供了两种使用缓存的方式,基于注解的缓存和基于编码的缓存。
基于注解的缓存
只需要将@CacheFor("5s")标记在action方法上,就能缓存方法返回的接口,这点和spring的缓存注解是一个道理。
基于编码的缓存
play提供了Cache类用于编码的缓存,并提供了常用的缓存操作如get、set、delete、incr、expire等
ps:Cache 一个缓存抽象类,聚合了一个缓存实现接口,并提供了多种缓存实现,方便用户切换
参考:cache - 1.5.x
3.7.2 集成了发送邮件的功能
参考:emails - 1.5.x
3.7.3 web安全问题
提供了如何避免常见的web安全问题:跨站脚本、跨站请求伪造、sql注入都是需要避免的问题。
参考:security - 1.5.x
3.7.4 代码热加载提高开发效率
play利用Eclipse提供的编译器,对代码进行了即时编译,并给予HotSpot做了热加载,所以不需要重启项目。
3.7.5 多种开箱即用的类库或工具
play有个强大的类库,提供了诸如OAuth2.0、异步http通信、安全、邮件、国际化等web开发的常用功能,在这里就不细说了,如果你对play感兴趣的话可以到他的官网去看看。
传送门: libs - 1.5.x
3.8 生产部署
3.8.1 多环境配置
通过play id 命令定义不同的环境前缀,然后将这些前缀配置的application.conf目录中,运行的时候指定要运行的环境即可,如下:
例如:
%dev.log.level=debug
%production.log.level=error
通过 play run --%production ,即可以production环境运行
四、该总结啦
优点:
1、高度封装的web框架,开发速度快。
2、因为是用的JPA访问数据库,不同数据库迁移方便。
3、适合敏捷开发,做后台管理系统很合适。
缺点:
1、感觉dao层不够强大,复杂的查询和统计,就得使用本地sql了。
2、项目构建和依赖管理不太方便。play2好像更换成了sbt了。
适用:
个人感觉适合前后端不分离的小项目会更好一些,短平快追求!
最后说一句,动起手来实践一下,你会收获很大!