§Play 2.5 迁移指南
本指南介绍如何从 Play 2.4 迁移到 Play 2.5。如果您需要从更早版本的 Play 迁移,则必须首先遵循 Play 2.4 迁移指南。
除了本页面的信息外,还有一些主题的更详细的迁移信息
- Streams 迁移指南 - 迁移到 Akka Streams,现在在许多 Play API 中代替了迭代器
- Java 迁移指南 - 迁移 Java 应用程序。Play 现在使用原生 Java 类型来表示函数类型,并在 Java 中提供了一些新的可定制组件。
Lucidchart 还发布了一篇关于 从 Play 2.3.x 升级到 Play 2.5.x 的信息丰富的博客文章。
§如何迁移
在您可以在 sbt 中加载/运行 Play 项目之前,需要执行以下步骤来更新您的 sbt 构建。
§Play 升级
更新 project/plugins.sbt 中的 Play 版本号以升级 Play
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.5.x")
其中 2.5.x 中的“x”是您要使用的 Play 的次要版本,例如 2.5.0。
§sbt 升级到 0.13.11
虽然 Play 2.5 仍然可以使用 sbt 0.13.8,但我们建议您升级到最新的 sbt 版本 0.13.11。sbt 的 0.13.11 版本包含许多 改进和错误修复。
更新您的 project/build.properties,使其读取
sbt.version=0.13.11
§Play Slick 升级
如果您的项目使用的是 Play Slick,则需要对其进行升级
libraryDependencies += "com.typesafe.play" %% "play-slick" % "2.0.0"
或
libraryDependencies ++= Seq(
"com.typesafe.play" %% "play-slick" % "2.0.0",
"com.typesafe.play" %% "play-slick-evolutions" % "2.0.0"
)
§Play Ebean 升级
如果您的项目使用 Play Ebean,您需要对其进行升级
addSbtPlugin("com.typesafe.sbt" % "sbt-play-ebean" % "3.0.0")
§ScalaTest + Play 升级
如果您的项目使用 ScalaTest + Play,您需要对其进行升级
libraryDependencies ++= Seq(
"org.scalatestplus.play" %% "scalatestplus-play" % "1.5.1" % "test"
)
§Scala 2.10 支持已停止
Play 2.3 和 2.4 同时支持 Scala 2.10 和 2.11。Play 2.5 已停止支持 Scala 2.10,现在仅支持 Scala 2.11。这有几个原因
-
Play 2.5 的内部代码广泛使用 scala-java8-compat 库,该库仅支持 Scala 2.11。scala-java8-compat 在许多 Scala 和 Java 8 类型之间进行转换,例如 Scala
Future和 JavaCompletionStage。(您可能会发现此库对您的代码也很有用。) -
Play 的下一个版本可能会添加对 Scala 2.12 的支持。现在是 Play 转向 Scala 2.11 的时候了,这样即将到来的 2.12 过渡将更容易。
§如何迁移
Scala 和 Java 用户都必须配置 sbt 以使用 Scala 2.11。即使您的项目中没有 Scala 代码,Play 本身也使用 Scala,并且必须配置为使用正确的 Scala 库。
要在 sbt 中设置 Scala 版本,只需设置 scalaVersion 键,例如
scalaVersion := "2.11.8"
如果您只有一个项目构建,那么此设置可以放在 build.sbt 中的单独一行上。但是,如果您有多个项目构建,那么必须在每个项目上设置 scala 版本设置。通常,在多个项目构建中,您将有一些由每个项目共享的通用设置,这是放置设置的最佳位置,例如
def common = Seq(
scalaVersion := "2.11.8"
)
lazy val projectA = (project in file("projectA"))
.enablePlugins(PlayJava)
.settings(common: _*)
lazy val projectB = (project in file("projectB"))
.enablePlugins(PlayJava)
.settings(common: _*)
§更改为 Logback 配置
作为删除 Play 对 Logback 的硬编码依赖项的更改的一部分 (参见亮点),Logback 配置使用的一个类必须移动到另一个包中。
§如何迁移
您需要更新您的 Logback 配置文件 (logback*.xml) 并将对旧的 play.api.Logger$ColoredLevel 的任何引用更改为新的 play.api.libs.logback.ColoredLevel 类。
更改后的新配置将如下所示
<conversionRule conversionWord="coloredLevel"
converterClass="play.api.libs.logback.ColoredLevel" />
如果您使用编译时依赖项注入,则需要将应用程序加载器从使用 Logger.configure(...) 更改为以下内容
LoggerConfigurator(context.environment.classLoader).foreach { _.configure(context.environment) }
您可以在文档的 配置日志 部分找到有关如何使用不同的日志框架设置 Play 的更多详细信息。
§Play WS 升级到 AsyncHttpClient 2
Play WS 已升级到使用 AsyncHttpClient 2。这是一个重大升级,它使用 Netty 4.0。AHC 2.0 中的大多数更改都在幕后进行,但 AHC 有一些重大的重构,需要对 WS API 进行重大更改。
AsyncHttpClientConfig被DefaultAsyncHttpClientConfig替换。allowPoolingConnection和allowSslConnectionPool在 AsyncHttpClient 中合并为单个keepAlive变量。因此,play.ws.ning.allowPoolingConnection和play.ws.ning.allowSslConnectionPool无效,如果配置了它们,将抛出异常。webSocketIdleTimeout已被移除,因此在AhcWSClientConfig中不再可用。ioThreadMultiplier已被移除,因此在AhcWSClientConfig中不再可用。FluentCaseInsensitiveStringsMap类已被移除,并被 Netty 的HttpHeader类替换。Realm.AuthScheme.None已被移除,因此在WSAuthScheme中不再可用。
此外,还有一些小的更改。
- 为了反映正确的 AsyncHttpClient 库名称,包
play.api.libs.ws.ning已重命名为play.api.libs.ws.ahc,Ning*类已重命名为Ahc*。此外,AHC 配置设置已更改为play.ws.ahc前缀,例如play.ws.ning.maxConnectionsPerHost现在是play.ws.ahc.maxConnectionsPerHost。 - 已移除已弃用的接口
play.libs.ws.WSRequestHolder。 play.libs.ws.play.WSRequest接口现在返回java.util.concurrent.CompletionStage而不是F.Promise。- 依赖于
Play.current或Play.application的静态方法已弃用。 - Play WS 会从内容类型推断字符集,并在请求的
Content-Type标头中追加字符集(如果尚未设置)。这会导致一些混淆和错误,因此在 2.5.x 中,Content-Type标头不会自动包含推断的字符集。如果您显式设置Content-Type标头,则会按原样保留设置。
§已弃用 GlobalSettings
作为 Play 逐步摆脱全局状态的努力的一部分,GlobalSettings 和应用程序 Global 对象已被弃用。有关更多详细信息,请参阅 Play 2.4 迁移指南,了解如何迁移以不再使用 GlobalSettings。
§已移除 Plugins API
Plugins API 在 Play 2.4 中已弃用,并在 Play 2.5 中被移除。Plugins API 已被 Play 的依赖注入和模块系统取代,该系统提供了一种更简洁、更灵活的方式来构建可重用的组件。有关如何从插件迁移到依赖注入的详细信息,请参阅 Play 2.4 迁移指南。
§使用 InjectedRoutesGenerator 生成的路由
路由现在使用依赖注入感知的 InjectedRoutesGenerator 生成,而不是之前的 StaticRoutesGenerator,该生成器假设控制器是单例对象。
要恢复到之前的行为(例如,如果您的代码中有“object MyController”),请将以下行添加到您的 build.sbt 文件中
routesGenerator := StaticRoutesGenerator
如果您使用的是 Build.scala 而不是 build.sbt,则需要导入 routesGenerator 设置键
import play.sbt.routes.RoutesCompiler.autoImport._
使用静态控制器和静态路由生成器并不被弃用,但建议您迁移到使用具有依赖注入的类。
§用依赖注入替换静态控制器
controllers.ExternalAssets 现在是一个类,没有静态等效项。controllers.Assets 和 controllers.Default 也是类,虽然存在静态等效项,但建议您使用类版本。
§如何迁移
推荐的解决方案是为所有控制器使用类。InjectedRoutesGenerator 现在是默认值,因此路由文件中的控制器被假定为类而不是对象。
如果您仍然有静态控制器,可以使用 StaticRoutesGenerator(如上所述)并在 routes 文件中路由的前面添加 @ 符号,例如
GET /assets/*file @controllers.ExternalAssets.at(path = "/public", file)
§已弃用的 play.Play 和 play.api.Play 方法
以下方法在 play.Play 中已被弃用
public static Application application()public static Mode mode()public static boolean isDev()public static boolean isProd()public static boolean isTest()
同样,play.api.Play 中使用隐式 Application 并委托给 Application 的方法,例如 def classloader(implicit app: Application) 现在已弃用。
§如何迁移
这些方法委托给 play.Application 或 play.Environment - 使用这些方法的代码应该使用依赖注入来注入相关类。
您应该参考 Play 2.4 迁移指南 中的依赖注入组件列表来迁移内置的 Play 组件。
例如,以下代码在 Scala 中将环境和配置注入到控制器中
class HomeController @Inject() (environment: play.api.Environment,
configuration: play.api.Configuration)
extends Controller {
def index = Action {
Ok(views.html.index("Your new application is ready."))
}
def config = Action {
Ok(configuration.underlying.getString("some.config"))
}
def count = Action {
val num = environment.resource("application.conf").toSeq.size
Ok(num.toString)
}
}
§处理遗留组件
通常您使用的组件不需要依赖于整个应用程序,但有时您必须处理需要应用程序的遗留组件。您可以通过将应用程序注入到您的其中一个组件中来处理这种情况
class FooController @Inject() (appProvider: Provider[Application])
extends Controller {
implicit lazy val app = appProvider.get()
def bar = Action {
Ok(Foo.bar(app))
}
}
请注意,在这种情况下,您通常希望使用 Provider[Application] 来避免循环依赖。
更好的是,您可以创建自己的 *Api 类,将静态方法转换为实例方法
class FooApi @Inject() (appProvider: Provider[Application]) {
implicit lazy val app = appProvider.get()
def bar = Foo.bar(app)
def baz = Foo.baz(app)
}
这使您能够从 DI 带来的可测试性中获益,同时仍然使用使用全局状态的库。
§Content-Type 字符集更改
在 Play 2.5 之前,Play 会向某些未定义字符集参数的 Content-Type 添加 charset 参数,特别是 application/json 和 application/x-www-form-urlencoded。现在,默认情况下,Content-Type 会在没有字符集的情况下发送。这适用于使用 WS 发送请求和从 Play 操作返回响应。如果您有一个非规范兼容的客户端或服务器,它要求您发送字符集参数,您可以显式设置 Content-Type 标头。
§Guice 注入器和 Guice 构建器更改
默认情况下,Guice 可以通过代理循环中的接口来解决循环依赖。由于循环依赖通常是代码异味,并且您也可以注入 Provider 来打破循环,因此我们选择在默认的 Guice 注入器上禁用此功能。其他 DI 框架也不太可能具有此功能,因此在编写 Play 模块时可能会导致问题。
现在,Guice 构建器(GuiceInjectorBuilder 和 GuiceApplicationBuilder)上有四种新方法,用于自定义 Guice 如何注入您的类。
* disableCircularProxies:禁用上述代理接口以解决循环依赖的行为。要允许代理,请使用 disableCircularProxies(false)。
* requireExplicitBindings:指示注入器仅注入在模块中显式绑定的类。在测试中验证绑定时可能很有用。
* requireAtInjectOnConstructors:要求使用 @Inject 注解的构造函数来实例化类。
* requireExactBindingAnnotations:禁用 Guice 中容易出错的功能,该功能可以在注入 @Named(“foo”) Foo 时用 @Named Foo 的绑定替换绑定。
§CSRF 更改
为了使 Play 的 CSRF 过滤器更能抵御浏览器插件漏洞和新扩展,CSRF 过滤器的默认配置已变得更加保守。更改包括
- 不再将
POST请求列入黑名单,现在只有GET、HEAD和OPTIONS请求被列入白名单,所有其他请求都需要 CSRF 检查。这意味着DELETE和PUT请求现在将被检查。 - 不再将
application/x-www-form-urlencoded、multipart/form-data和text/plain请求列入黑名单,所有内容类型的请求,包括没有内容类型的请求,都需要 CSRF 检查。这会导致使用application/json的 AJAX 请求现在需要在Csrf-Token标头中包含有效的 CSRF 令牌。 - 无状态的基于标头的绕过,例如
X-Requested-With,默认情况下被禁用。
有一个新的配置选项可以绕过对具有某些标头的请求的新 CSRF 保护。此配置选项默认情况下为 Cookie 和 Authorization 标头启用,因此通常不使用会话身份验证的 REST 客户端仍然可以工作,而无需发送 CSRF 令牌。
但是,由于配置选项允许通过所有没有这些标头的请求,因此使用其他身份验证方案(NTLM、TLS 客户端证书)的应用程序将容易受到 CSRF 的攻击。这些应用程序应禁用配置选项,以便其经过身份验证的(无 cookie)请求受到 CSRF 过滤器的保护。
最后,添加了一个额外的选项,用于禁用 CORS 过滤器信任的来源的 CSRF 检查。请注意,CORS 过滤器必须在您的过滤器链中位于 CSRF 过滤器**之前**,才能使此功能生效!
可以通过在 application.conf 中添加以下配置来恢复 Play 的旧默认行为
play.filters.csrf {
header {
bypassHeaders {
X-Requested-With = "*"
Csrf-Token = "nocheck"
}
protectHeaders = null
}
bypassCorsTrustedOrigins = false
method {
whiteList = []
blackList = ["POST"]
}
contentType.blackList = ["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"]
}
§获取 CSRF 令牌
以前,可以在任何操作中从 HTTP 请求中检索 CSRF 令牌。现在,您必须拥有 CSRF 过滤器或 CSRF 操作才能使 CSRF.getToken 工作。如果您没有使用过滤器,可以使用 Scala 中的 CSRFAddToken 操作或 Java 中的 AddCSRFToken 注解来确保会话中存在令牌。
此外,此版本修复了一个小错误,该错误会导致 CSRF 令牌为空(在模板助手中抛出异常),如果其签名无效。现在它将在同一个请求中重新生成,因此模板助手和 CSRF.getToken 仍然可以从令牌中获取。
有关更多详细信息,请阅读有关 Java 和 Scala 的 CSRF 文档。
§Crypto 已弃用
从 Play 1.x 开始,Play 附带了一个 Crypto 对象,它提供了一些加密操作。Play 在内部使用它。Crypto 对象未在文档中提及,但在 scaladoc 中被提及为“加密实用程序”。
由于各种原因,提供加密实用程序作为便利措施已被证明不可行。在 2.5.x 中,Play 特定的功能已分解为 CookieSigner、CSRFTokenSigner 和 AESSigner 特性,并且 Crypto 单例对象已弃用。
§如何迁移
加密迁移将取决于您的用例,尤其是如果存在对加密原语的不安全构造。简而言之,如果可能,请使用 Kalium,否则请使用 Tink 或直接使用 JCA。
有关更多详细信息,请参阅 加密迁移。
§Netty 4 升级
Netty 已从 3.10 升级到 4.0。 这导致配置 Netty 通道选项的配置选项发生了变化。 完整的选项列表可以在 此处 查看。
§如何迁移
修改任何 play.server.netty.option 键以使用 ChannelOption 中定义的新键。 一些常用键的映射如下:
| 旧的 | 新的 |
|---|---|
play.server.netty.option.backlog |
play.server.netty.option.SO_BACKLOG |
play.server.netty.option.child.keepAlive |
play.server.netty.option.child.SO_KEEPALIVE |
play.server.netty.option.child.tcpNoDelay |
play.server.netty.option.child.TCP_NODELAY |
§sendFile、sendPath 和 sendResource 方法的更改
Java (play.mvc.StatusHeader) 和 Scala (play.api.mvc.Results.Status) API 在之前具有以下行为:
| API | 方法 | 默认值 |
|---|---|---|
| Scala | play.api.mvc.Results.Status.sendResource |
内联 |
| Scala | play.api.mvc.Results.Status.sendPath |
附件 |
| Scala | play.api.mvc.Results.Status.sendFile |
附件 |
| Java | play.mvc.StatusHeader.sendInputStream |
无 |
| Java | play.mvc.StatusHeader.sendResource |
内联 |
| Java | play.mvc.StatusHeader.sendPath |
附件 |
| Java | play.mvc.StatusHeader.sendFile |
内联 |
换句话说,它们在传递文件时混合了 inline 和 attachment 模式。 现在,在传递文件、路径和资源时,使用 inline 作为默认行为。 当然,您可以使用这些方法中提供的参数在两种模式之间进行切换。
下一步:流迁移指南
发现此文档中的错误? 此页面的源代码可以在 此处 找到。 在阅读 文档指南 后,请随时贡献拉取请求。 有问题或建议要分享? 转到 我们的社区论坛 与社区开始对话。