§Play 2.3 迁移指南
本指南介绍如何从 Play 2.2 迁移到 Play 2.3。如果您需要从更早版本的 Play 迁移,则必须首先遵循 Play 2.2 迁移指南。
§Activator
在 Play 2.3 中,play
命令已变为 activator
命令。Play 已更新为使用 Activator。
§Activator 命令
play
命令中提供的所有功能仍然可以通过 activator
命令使用。
activator new
用于创建新项目。请参阅 创建新应用程序。activator
用于运行控制台。请参阅 使用 Play 控制台。activator ui
是一个新命令,用于启动 Web 用户界面。
新的
activator
命令和旧的play
命令都是 sbt 的包装器。如果您愿意,可以直接使用sbt
命令。但是,如果您使用 sbt,您将错过 Activator 的一些功能,例如模板 (activator new
) 和 Web 用户界面 (activator ui
)。sbt 和 Activator 都支持所有常用的控制台命令,例如test
和run
。
§Activator 分发
Play 作为包含所有 Play 依赖项的 Activator 分发版进行分发。您可以从 Play 下载 页面下载此分发版。
如果您愿意,您也可以从 Activator 网站 下载 Activator 的最小 (1MB) 版本。在下载页面上查找“mini”分发版。Activator 的最小版本仅在需要时才会下载依赖项。
由于 Activator 是 sbt 的包装器,因此如果您愿意,您也可以直接下载和使用 sbt。
§构建更改
§sbt
Play 使用 sbt 0.13.5。如果您正在更新现有项目,请将您的 project/build.properties
文件更改为
sbt.version=0.13.5
§插件更改
更改 project/plugins.sbt
中 Play 插件的版本
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.3.XXX")
其中 2.3.XXX
是您要使用的 Play 版本。
您还需要添加一些 sbt-web 插件,请参阅下面的“sbt-web”部分。
§自动插件和插件设置
sbt 0.13.5 带来了一个名为“自动插件”的新功能。
自动插件允许 sbt 插件像以前一样在 project
文件夹(通常是 plugins.sbt
)中声明。但是,现在插件可以声明它们对其他插件的要求以及触发它们针对给定构建的启用方式。在自动插件之前,添加到构建中的插件始终可用;现在,插件会针对给定模块选择性地启用。
这对您意味着,对于现在利用自动插件功能的插件,声明 addSbtPlugin
可能不足够。这是一件好事。您现在可以选择项目中的哪些模块应该使用哪些插件,例如
lazy val root = (project in file(".")).enablePlugins(SbtWeb)
上面的示例显示 SbtWeb
被添加到构建的根项目中。在 SbtWeb
的情况下,如果它被启用,则会启用其他插件,例如,如果您还通过 addSbtPlugin
添加了 sbt-less-plugin
,那么它将仅因为 SbtWeb
已被启用而被启用。因此,SbtWeb
是该类插件的“根”插件。
Play 本身现在使用自动插件机制添加。Play 2.2 中使用 playJavaSettings
和 playScalaSettings
的机制已被删除。您现在可以使用以下方法之一代替
lazy val root = (project in file(".")).enablePlugins(PlayJava)
或
lazy val root = (project in file(".")).enablePlugins(PlayScala)
如果您之前使用的是 play.Project,例如 Scala 项目
object ApplicationBuild extends Build {
val appName = "myproject"
val appVersion = "1.0-SNAPSHOT"
val appDependencies = Seq()
val main = play.Project(appName, appVersion, appDependencies).settings(
)
}
…那么您可以继续使用类似的方法通过原生 sbt
object ApplicationBuild extends Build {
val appName = "myproject"
val appVersion = "1.0-SNAPSHOT"
val appDependencies = Seq()
val main = Project(appName, file(".")).enablePlugins(play.PlayScala).settings(
version := appVersion,
libraryDependencies ++= appDependencies
)
}
通过迁移到上述样式,设置现在在启用插件时会自动导入。
Play 提供的键现在也必须在 PlayKeys
对象中引用。例如,要引用 playVersion
,您必须通过导入
import PlayKeys._
或使用 PlayKeys.playVersion
限定它。
除了使用 .sbt
文件,例如如果您使用 Scala 来描述您的构建,那么您可以执行以下操作来将 PlayKeys
放在作用域内
import play.Play.autoImport._
import PlayKeys._
§显式 scalaVersion
Play 2.3 支持 Scala 2.11 和 Scala 2.10。Play 插件以前为您设置 scalaVersion
sbt 设置。现在您应该指定要使用的 Scala 版本。
更新您的 build.sbt
或 Build.scala
以包含 Scala 版本
对于 Scala 2.11
scalaVersion := "2.11.1"
对于 Scala 2.10
scalaVersion := "2.10.4"
§sbt-web
Play 2.3 最大的新功能是引入了 sbt-web。总而言之,sbt-web 允许将 Html、CSS 和 JavaScript 功能从 Play 的核心分解为一系列纯 sbt 插件。这对您来说有两个主要优势
- Play 对 Html、CSS 和 JavaScript 的意见更少;并且
- sbt-web 可以拥有自己的社区,并与 Play 平行发展。
还有其他优势,包括 sbt-web 插件能够通过 Trireme 在 JVM 中运行,或者使用 Node.js 本地运行。请注意,sbt-web 是一个开发环境,不参与 Play 应用程序的执行。默认情况下使用 Trireme,但如果您安装了 Node.js 并希望为您的构建提供极快的性能,那么您可以通过 sbt 的 SBT_OPTS 环境变量提供系统属性。例如
export SBT_OPTS="$SBT_OPTS -Dsbt.jse.engineType=Node"
sbt-web 的一个特性是它不关心您使用的是“javascripts”还是“stylesheets”作为您的文件夹名称。任何具有适当文件名扩展名的文件都将从 app/assets
文件夹中过滤出来。
sbt-web 的一个细微差别是,所有 资产都从 public
文件夹提供服务。因此,如果您以前将资产放在 public
文件夹之外,例如您使用 playAssetsDirectories
设置,如下例所示
playAssetsDirectories <+= baseDirectory / "foo"
…那么您现在应该使用以下内容
unmanagedResourceDirectories in Assets += baseDirectory.value / "foo"
…但是请注意,那里的文件将被聚合到目标 public 文件夹中。这意味着“public/a.js”中的文件将被“foo/a.js”中的文件覆盖。或者,使用项目 public 文件夹的子文件夹来对它们进行命名空间。
以下列出了所有与 sbt-web 相关的组件及其在发布 Play 2.3 时版本。
§库
"com.typesafe" %% "webdriver" % "1.0.0"
"com.typesafe" %% "jse" % "1.0.0"
"com.typesafe" %% "npm" % "1.0.0"
§sbt 插件
"com.typesafe.sbt" % "sbt-web" % "1.0.0"
"com.typesafe.sbt" % "sbt-webdriver" % "1.0.0"
"com.typesafe.sbt" % "sbt-js-engine" % "1.0.0"
"com.typesafe.sbt" % "sbt-coffeescript" % "1.0.0"
"com.typesafe.sbt" % "sbt-digest" % "1.0.0"
"com.typesafe.sbt" % "sbt-gzip" % "1.0.0"
"com.typesafe.sbt" % "sbt-less" % "1.0.0"
"com.typesafe.sbt" % "sbt-jshint" % "1.0.0"
"com.typesafe.sbt" % "sbt-mocha" % "1.0.0"
"com.typesafe.sbt" % "sbt-rjs" % "1.0.1"
§WebJars
WebJars 现在在为 Play 应用程序提供资源方面发挥着重要作用。例如,您可以通过在构建文件中添加以下依赖项来声明您将使用流行的 Bootstrap 库
libraryDependencies += "org.webjars" % "bootstrap" % "3.2.0"
为了方便起见,WebJars 会自动提取到相对于您的公共资源的 lib
文件夹中。例如,如果您声明了对 RequireJs 的依赖,那么您可以使用类似以下的代码行从视图中引用它
<script data-main="@routes.Assets.at("javascripts/main.js")" type="text/javascript" src="@routes.Assets.at("lib/requirejs/require.js")"></script>
请注意 lib/requirejs/require.js
路径。lib
文件夹表示提取的 WebJar 资源,requirejs
文件夹对应于 WebJar 的 artifactId,require.js
指的是 WebJar 根目录中所需的资源。
§npm
通过在项目的根目录中声明 package.json
文件,可以使用 npm 以及 WebJars。来自 npm 包的资源将提取到与 WebJars 相同的 lib
文件夹中,因此从代码的角度来看,无需担心资源是来自 WebJar 还是来自 npm 包。
从您的角度来看,我们的目标是提供与 Play 以前版本的功能一致性。虽然内部发生了重大变化,但您的过渡应该很小。本节的其余部分将介绍 Play 中每个被 sbt-web 替换的部分,并描述应该进行哪些更改。
§CoffeeScript
您现在必须声明插件,通常在您的 plugins.sbt 文件中
addSbtPlugin("com.typesafe.sbt" % "sbt-coffeescript" % "1.0.0")
Coffeescript 选项已更改。新的选项是
sourceMap
设置后,会生成 sourceMap 文件。默认为true
。
CoffeeScriptKeys.sourceMap := true
bare
设置后,会生成没有 顶层函数安全包装器 的 JavaScript。默认为false
。
CoffeeScriptKeys.bare := false
有关更多信息,请参阅 插件的文档。
§LESS
您现在必须声明插件,通常在您的 plugins.sbt 文件中
addSbtPlugin("com.typesafe.sbt" % "sbt-less" % "1.0.0")
现在使用过滤器声明入口点。例如,要声明 foo.less
和 bar.less
是必需的
includeFilter in (Assets, LessKeys.less) := "foo.less" | "bar.less"
如果您以前使用的是在 less 文件名前面带有下划线的文件被忽略,但所有其他 less 文件都被编译的行为,那么请使用以下过滤器
includeFilter in (Assets, LessKeys.less) := "*.less"
excludeFilter in (Assets, LessKeys.less) := "_*.less"
与 Play 2.2 不同,sbt-less 插件允许任何用户下载原始 LESS 源文件和生成的源映射。它允许在现代 Web 浏览器中更轻松地调试。即使在生产模式下,此功能也是启用的。
插件的选项是
选项 | 描述 |
---|---|
cleancss | 使用 clean-css 压缩输出。 |
cleancssOptions | 使用来自 https://github.com/GoalSmashers/clean-css 的 CLI 参数,将选项传递给 clean css。 |
color | LESS 输出是否应彩色化 |
compress | 通过删除一些空格来压缩输出。 |
ieCompat | 执行 IE 兼容性检查。 |
insecure | 允许从不安全的 https 主机导入。 |
maxLineLen | 最大行长。 |
optimization | 设置解析器的优化级别。 |
relativeUrls | 将相对 URL 重写为基本 less 文件。 |
rootpath | 为相对导入和 URL 中的 URL 重写设置 rootpath。 |
silent | 抑制错误消息的输出。 |
sourceMap | 输出 v3 源映射。 |
sourceMapFileInline | 源映射是否应嵌入到输出文件中 |
sourceMapLessInline | 是否将 less 代码嵌入到源映射中 |
sourceMapRootpath | 将此路径添加到源映射文件名和 less 文件路径。 |
strictImports | 导入是否应严格。 |
strictMath | 需要括号。此选项可能默认为 true 并在将来删除。 |
strictUnits | 所有单位是否应严格,或者是否允许混合单位。 |
verbose | 详细。 |
有关更多信息,请参阅 插件文档。
§Closure 编译器
Closure 编译器已被替换。它验证 JavaScript 和对其进行缩小的两个重要功能已分别分解为 JSHint 和 UglifyJS 2。
要使用 JSHint,您必须声明它,通常在您的 plugins.sbt 文件中
addSbtPlugin("com.typesafe.sbt" % "sbt-jshint" % "1.0.0")
可以根据 JSHint 网站 指定选项,它们共享相同的默认值集。要设置选项,您可以在项目的基目录中提供一个 .jshintrc
文件。如果没有这样的文件,则将在您的主目录中搜索 .jshintrc
文件。此行为可以通过使用插件的 JshintKeys.config
设置来覆盖。JshintKeys.config
用于指定配置文件的位置。
有关更多信息,请参阅 插件文档。
UglifyJS 2 目前通过 RequireJS 插件提供(将在下面描述)。未来的目标是为不使用 RequireJS 的情况提供一个独立的 UglifyJS 2 插件。
§RequireJS
RequireJS Optimizer (rjs) 已完全替换为一个更易于使用的版本。新的 rjs 是 sbt-web 的资产管道功能的一部分。与它的前身不同,前身在每次构建时都会被调用,而新的 rjs 仅在通过 Play 的 stage
或 dist
任务生成发行版时才会被调用。
要使用 rjs,您必须声明它,通常在您的 plugins.sbt 文件中
addSbtPlugin("com.typesafe.sbt" % "sbt-rjs" % "1.0.1")
要将插件添加到资产管道,您可以按如下方式声明它
pipelineStages := Seq(rjs)
我们还建议将 sbt-web 的 sbt-digest 和 sbt-gzip 插件包含在管道中。sbt-digest 将为 Play 的资产控制器提供为远期缓存对资产名称进行指纹识别功能。sbt-gzip 会生成您的资产的 gzip 版本,资产控制器在请求时会优先使用它。此配置的 plugins.sbt 文件将如下所示
addSbtPlugin("com.typesafe.sbt" % "sbt-digest" % "1.0.0")
addSbtPlugin("com.typesafe.sbt" % "sbt-gzip" % "1.0.0")
您的管道配置现在变为
pipelineStages := Seq(rjs, digest, gzip)
阶段的顺序很重要。您首先要优化文件,生成它们的摘要,然后生成所有结果资产的 gzip 版本。
RequireJs 优化的选项已完全改变。插件的选项是
选项 | 描述 |
---|---|
appBuildProfile | 项目构建配置文件内容。 |
appDir | 包含您的应用程序 js 文件的顶层目录。实际上,这是 rjs 读取的源文件夹。 |
baseUrl | 相对于资产或公共文件夹的目录,其中包含 js 文件。将默认为“js”、“javascripts”或“.”,如果前两个找不到,则默认为“.”。 |
buildProfile | 构建配置文件键 -> 值设置,除了 appBuildProfile 提供的默认值之外。此处的任何设置也将替换任何默认值。 |
dir | 默认情况下,所有模块都位于此路径的相对位置。实际上,这是 rjs 的目标目录。 |
generateSourceMaps | 默认情况下,会生成源映射。 |
mainConfig | 默认情况下,使用“main”作为配置模块。 |
mainConfigFile | 以上内容的完整路径。 |
mainModule | 默认情况下,使用“main”作为模块。 |
modules | 模块的 json 数组。 |
optimize | 优化器的名称,默认为 uglify2。 |
paths | 模块 ID 到构建路径和生产路径元组的 RequireJS 路径映射。默认情况下,所有 WebJar 库都可从 CDN 获取,并且它们的映射可以在此处找到(除非 cdn 设置为 None)。 |
preserveLicenseComments | 是否保留注释。默认情况下,在源映射的情况下为 false(参见 https://requirejs.node.org.cn/docs/errors.html#sourcemapcomments))。 |
webJarCdns | 用于定位 WebJars 的 CDN。默认情况下,“org.webjars”映射到“jsdelivr”。 |
webJarModuleIds | 要使用的 webjar 模块 ID 序列。 |
有关更多信息,请参阅 插件文档。
§默认 ivy 本地仓库和缓存
由于 Play 现在使用 Activator 作为启动器,因此它现在使用默认的 ivy 缓存和本地仓库。这意味着之前发布到 Play ivy 缓存中并依赖的任何内容都需要发布到主目录中 .ivy2
文件夹中的本地 ivy 仓库中。
§结果重构
在 Play 2.2 中,许多结果类型已弃用,为了便于迁移到新的结果结构,引入了一些新类型。Play 2.3 完成了此重构。
§Scala 结果
以下 Play 2.1 中已弃用的类型和帮助程序已删除
play.api.mvc.PlainResult
play.api.mvc.ChunkedResult
play.api.mvc.AsyncResult
play.api.mvc.Async
如果您的代码仍在使用这些类型,请参阅 Play 2.2 迁移指南,了解如何迁移到新的结果结构。
如 2.2 中的计划,2.3 已将 play.api.mvc.SimpleResult
重命名为 play.api.mvc.Result
(替换现有的 Result
特性)。已引入类型别名以方便迁移,因此您的 Play 2.2 代码应与 Play 2.3 源代码兼容,但是我们最终将删除此类型别名,因此我们已将其弃用,并建议切换到 Result
。
§Java 结果
以下 Play 2.1 中已弃用的类型和帮助程序已删除
play.mvc.Results.async
play.mvc.Results.AsyncResult
如果您的代码仍在使用这些类型,请参阅 Play 2.2 迁移指南,了解如何迁移到新的结果结构。
如 2.2 中的计划,2.3 已将 play.mvc.SimpleResult
重命名为 play.mvc.Result
。这对于大多数 Java 代码来说应该是透明的。这将影响的最显着的地方是在 Global.java
错误回调中以及在自定义操作中。
§模板
模板引擎现在是一个独立的项目,Twirl。
§内容类型
模板内容类型已移至 twirl 包。如果引用了 play.mvc.Content
类型,则需要将其更新为 play.twirl.api.Content
。例如,Play Java 项目中的以下代码
import play.mvc.Content;
Content html = views.html.index.render("42");
将产生错误
[error] ...: incompatible types
[error] found : play.twirl.api.Html
[error] required: play.mvc.Content
并且需要导入play.twirl.api.Content
。
§sbt 设置
模板的 sbt 设置现在由 sbt-twirl 插件提供。
以前,在模板中添加额外的导入是
templatesImport += "com.abc.backend._"
现在是
TwirlKeys.templateImports += "org.abc.backend._"
以前,指定自定义模板格式是
templatesTypes += ("html" -> "my.HtmlFormat.instance")
现在是
TwirlKeys.templateFormats += ("html" -> "my.HtmlFormat.instance")
对于使用完整 Scala 语法的 sbt 构建,可以使用以下方法导入 TwirlKeys
:
import play.twirl.sbt.Import._
§Html.empty 被 HtmlFormat.empty 替换
如果您之前使用的是 Html.empty
(play.api.templates.Html.empty
),现在必须使用 play.twirl.api.HtmlFormat.empty
。
§Play WS
WS 客户端现在是一个可选库。如果您在项目中使用 WS,则需要添加库依赖项。对于 Java 项目,您还需要更新到新的包。
§Java 项目
将库依赖项添加到 build.sbt
libraryDependencies += javaWs
在源文件中更新到新的库包
import play.libs.ws.*;
§Scala 项目
将库依赖项添加到 build.sbt
libraryDependencies += ws
此外,使用 WS 客户端现在需要 Play 应用程序在范围内。通常,这是通过添加以下内容来实现的
import play.api.Play.current
WS API 已经略有改变,WS.client
现在返回 WSClient
的实例,而不是底层的 AsyncHttpClient
对象。您可以通过调用 WS.client.underlying
来获取 AsyncHttpClient
。
§Anorm
此新版本中包含了 Anorm 的各种更改。
为了提高类型安全性,查询参数的类型必须可见,以便能够正确转换。现在,使用 Any
作为参数值(显式或由于擦除),会导致编译错误 No implicit view available from Any => anorm.ParameterValue
。
// Wrong
val p: Any = "strAsAny"
SQL("SELECT * FROM test WHERE id={id}").
on('id -> p) // Erroneous - No conversion Any => ParameterValue
// Right
val p = "strAsString"
SQL("SELECT * FROM test WHERE id={id}").on('id -> p)
// Wrong
val ps = Seq("a", "b", 3) // inferred as Seq[Any]
SQL("SELECT * FROM test WHERE (a={a} AND b={b}) OR c={c}").
on('a -> ps(0), // ps(0) - No conversion Any => ParameterValue
'b -> ps(1),
'c -> ps(2))
// Right
val ps = Seq[anorm.ParameterValue]("a", "b", 3) // Seq[ParameterValue]
SQL("SELECT * FROM test WHERE (a={a} AND b={b}) OR c={c}").
on('a -> ps(0), 'b -> ps(1), 'c -> ps(2))
如果需要在没有安全转换的情况下传递值,可以使用 anorm.Object(anyVal)
来设置不透明参数。
此外,参数值的擦除问题已修复:类型不再是 ParameterValue[_]
,而是 ParameterValue
。
参数名称的类型也已统一(使用 .on(...)
时)。现在仅支持 String
和 Symbol
作为名称。
类型 Pk[A]
已被弃用。您仍然可以将其用作列映射,但需要显式传递 Id[A]
或 NotAssigned
作为查询参数(作为类型安全性改进的结果)
// Column mapping, deprecated but Ok
val pk: Pk[Long] = SQL("SELECT id FROM test WHERE name={n}").
on('n -> "mine").as(get[Pk[Long]].single)
// Wrong parameter
val pkParam: Pk[Long] = Id(1l)
val name1 = "Name #1"
SQL"INSERT INTO test(id, name) VALUES($pkParam, $name1)".execute()
// ... pkParam is passed as Pk in query parameter,
// which is now wrong as a parameter type (won't compile)
// Right parameter Id
val idParam: Id[Long] = Id(2l) // same as pkParam but keep explicit Id type
val name2 = "Name #2"
SQL"INSERT INTO test(id, name) VALUES($idParam, $name2)".execute()
// Right parameter NotAssigned
val name2 = "Name #3"
SQL"INSERT INTO test(id, name) VALUES($NotAssigned, $name2)".execute()
由于已弃用的 Pk[A]
与 Option[A]
类似,而 Anorm 在列映射和作为查询参数时支持 Option[A]
,因此建议用 Some[A]
替换 Id[A]
,用 None
替换 NotAssigned
。
// Column mapping, deprecated but Ok
val pk: Option[Long] = SQL("SELECT id FROM test WHERE name={n}").
on('n -> "mine").as(get[Option[Long]].single)
// Assigned primary key as parameter
val idParam: Option[Long] = Some(2l)
val name1 = "Id"
SQL"INSERT INTO test(id, name) VALUES($idParam, $name1)".execute()
// Right parameter NotAssigned
val name2 = "NotAssigned"
SQL"INSERT INTO test(id, name) VALUES($None, $name2)".execute()
§Bootstrap
内置的 Bootstrap 字段构造函数已弃用,将在 Play 的未来版本中删除。
这有几个原因,其中一个原因是,我们发现 Bootstrap 在不同版本之间以及在不同版本之间变化太大,以至于 Play 提供的任何内置支持很快就会变得过时,并且与当前的 Bootstrap 版本不兼容。
另一个原因是,当前 Bootstrap 对 CSS 类别的要求无法仅用 Play 的字段构造函数实现,还需要自定义输入模板。
我们未来的观点是,如果这是一个对社区有价值的功能,可以创建一个第三方模块,该模块提供一组独立的 Bootstrap 表单帮助程序模板,这些模板特定于给定的 Bootstrap 版本,从而提供比目前更好的用户体验。
§会话超时
会话超时配置项 session.maxAge
以前是一个整数,定义为秒。现在它是一个持续时间,因此可以使用 1h
或 30m
等值指定。不幸的是,如果未指定时间单位,则默认单位为毫秒,这意味着配置值为 3600
以前被视为一小时,但现在被视为 3.6 秒。您需要更新您的配置以添加时间单位。
§Java JUnit 父类
Java WithApplication
、WithServer
和 WithBrowser
JUnit 测试父类已修改为定义一个 @Before
注释方法。这意味着,以前您必须通过定义来显式启动应用程序
@Before
public void setUp() {
start();
}
现在您不需要这样做。如果您需要提供自定义应用程序,可以通过覆盖 provideFakeApplication
方法来实现
@Override
protected Application provideFakeApplication() {
return Helpers.fakeApplication(Helpers.inMemoryDatabase());
}
§会话和闪存隐式
Scala 控制器提供隐式 Session
、Flash
和 Lang
参数,它们接受一个隐式 RequestHeader
。这些参数是为了方便起见,例如,模板可以接受一个隐式参数,它们将在控制器中自动提供。这些参数的名称已更改,以避免与应用程序本地变量同名而导致的冲突。session
变成了 request2Session
,flash
变成了 flash2Session
,lang
变成了 lang2Session
。任何显式调用这些参数的代码都会因此而失效。
不建议您显式调用这些隐式方法,session
、flash
和 lang
参数在 RequestHeader
上都可用,使用 RequestHeader
属性可以更清楚地了解它们在代码中的来源。建议您如果代码使用旧方法,请修改代码以直接访问 RequestHeader
上的对应属性。
下一步: Play 2.2
发现此文档中的错误?此页面源代码可在 此处 找到。在阅读 文档指南 后,请随时贡献拉取请求。有任何问题或建议要分享?请访问 我们的社区论坛,与社区进行交流。