§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
作为默认行为。 当然,您可以使用这些方法中提供的参数在两种模式之间进行切换。
下一步:流迁移指南
发现此文档中的错误? 此页面的源代码可以在 此处 找到。 在阅读 文档指南 后,请随时贡献拉取请求。 有问题或建议要分享? 转到 我们的社区论坛 与社区开始对话。