【问题标题】:Play 2.4: Form: could not find implicit value for parameter messages: play.api.i18n.Messages播放 2.4:表单:找不到参数消息的隐式值:play.api.i18n.Messages
【发布时间】:2015-08-28 06:45:47
【问题描述】:

我是 Play 框架的新手,并尝试在本地机器上模仿 helloworld 示例,但遇到了错误:

路线:

# Home page
GET        /                    controllers.Application.index

# Hello action
GET        /hello               controllers.Application.sayHello


# Map static resources from the /public folder to the /assets URL path
GET        /assets/*file        controllers.Assets.versioned(path="/public", file: Asset)

控制者:

package controllers

import play.api.mvc._
import play.api.data._
import play.api.data.Forms._

import views._

class Application extends Controller {

  val helloForm = Form(
    tuple(
      "name" -> nonEmptyText,
      "repeat" -> number(min = 1, max = 100),
      "color" -> optional(text)
    )
  )

  def index = Action {
    Ok(html.index(helloForm))
  }

  def sayHello = Action { implicit request =>
      helloForm.bindFromRequest.fold(
      formWithErrors => BadRequest(html.index(formWithErrors)),
      {case (name, repeat, color) => Ok(html.hello(name, repeat.toInt, color))}
    )
  }
}

查看:

@(helloForm: Form[(String,Int,Option[String])])

@import helper._

@main(title = "The 'helloworld' application") { 
    <h1>Configure your 'Hello world':</h1> 
    @form(action = routes.Application.sayHello, args = 'id -> "helloform") {
        @inputText(
            field = helloForm("name"),
            args = '_label -> "What's your name?", 'placeholder -> "World"
        )

        @inputText(
            field = helloForm("repeat"),
            args = '_label -> "How many times?", 'size -> 3, 'placeholder -> 10
        ) 
        @select(
            field = helloForm("color"),
            options = options(
                "" -> "Default",
                "red" -> "Red",
                "green" -> "Green",
                "blue" -> "Blue"
            ),
            args = '_label -> "Choose a color"
        ) 
        <p class="buttons">
            <input type="submit" id="submit">
        <p> 
    } 
}

我安装了 Play 2.4,并通过 activator 模板使用 IntelliJ Idea 14 创建了项目。

【问题讨论】:

    标签: forms scala playframework playframework-2.4


    【解决方案1】:

    implicit messages 参数添加到视图后,您只需添加以下导入并使用旧的控制器类甚至对象,无需任何额外更改:

    import play.api.Play.current
    import play.api.i18n.Messages.Implicits._
    

    【讨论】:

    • 为什么这不是文档推荐的方法?这似乎比扩展 I18Support 和注入 MessagesApi 简单得多
    • 我想 Play Framework 开发人员会尝试推广更可定制的新方法。导入 play.api.i18n.Messages.Implicits._ 值会引入对 Play 消息传递提供程序的硬编码依赖。依赖项未参数化,这在某些情况下不方便,例如用于编写独立的单元测试。因此,使用具有参数化依赖关系的控制器类的方法更加简洁。不过,在我的应用程序中,通常使用带有硬编码依赖项的老式控制器 objects 就足够了。我更喜欢使用更简单的解决方案。
    • 可能值得一提的是,随着 play 的全局状态的移除,这种方法将被弃用。见Migration Guide / Dependency Injection
    • 谢谢!这是转向新方法的一个很好的理由。
    【解决方案2】:

    使用视图表单助手(例如@inputText)需要您将隐式play.api.i18n.Messages 参数传递给您的视图。您可以在视图中将(implicit messages: Messages) 添加到签名中。你的观点变成了这样:

    @(helloForm: Form[(String,Int,Option[String])])(implicit messages: Messages)
    
    @import helper._
    
    @main(title = "The 'helloworld' application") { 
      <h1>Configure your 'Hello world':</h1> 
      ...
    

    然后在您的应用程序控制器中,您必须使此参数在您的范围内隐式可用。最简单的方法是实现 play 的 I18nSupport 特征。

    在您的示例中,如下所示:

    package controllers
    
    import play.api.mvc._
    import play.api.data._
    import play.api.data.Forms._
    import javax.inject.Inject
    import play.api.i18n.I18nSupport
    import play.api.i18n.MessagesApi
    
    import views._
    
    class Application @Inject()(val messagesApi: MessagesApi) extends Controller with I18nSupport {
    
      val helloForm = Form(
        tuple(
          "name" -> nonEmptyText,
          "repeat" -> number(min = 1, max = 100),
          "color" -> optional(text)
        )
      )
    
      def index = Action {
        Ok(html.index(helloForm))
      }
    
      def sayHello = Action { implicit request =>
        helloForm.bindFromRequest.fold(
          formWithErrors => BadRequest(html.index(formWithErrors)),
          {case (name, repeat, color) => Ok(html.hello(name, repeat.toInt, color))}
        )
      }
    }
    

    在您的控制器中,您当然可以使用您自己的MessagesApi 实现。由于 play 开箱即用地知道如何注入 MessagesApi,因此您可以简单地使用 @Inject 注释您的控制器,然后让 play 为您完成工作。

    正如 Matthias Braun 所说,您还必须设置

    routesGenerator := InjectedRoutesGenerator
    

    在你的build.sbt

    有关 I18n 的更多信息,请参阅 https://www.playframework.com/documentation/2.4.x/ScalaI18N

    【讨论】:

    • 我已经有了:class AppController @Inject() (val messages: MessagesApi) extends Controller with I18nSupport { ... }。如果我正确理解了答案,那就足够了——但我仍然会收到该消息。
    • @MichaelA。将 val messages: MessagesApi 更改为 val messagesApi: MessagesApi。这将自动覆盖在I18nSupport 中定义的abstract def messagesApi
    • 多哈。现在工作 - 一千谢谢。其中一种错误可能会花费数小时盯着...
    • 为了让它工作,我必须将routesGenerator := InjectedRoutesGenerator 添加到我的build.sbt 并在路由到我的控制器前加上@: GET /hello @controllers.Application.sayHello
    • 我还必须添加 import play.api.i18n.I18nSupportimport play.api.i18n.MessagesApi 才能让它工作。
    【解决方案3】:

    使用表单助手需要您将隐式 play.api.i18n.Messages 参数传递给您的视图。您可以在视图中添加(implicit messages: Messages)。你的观点变成了这样:

    @(contacts: List[models.Contact], 
      form: Form[models.Contact])(implicit messages: Messages)
    

    然后手动注入你的控制器

    import play.api.data.Forms._
    
    import javax.inject.Inject
    
    import play.api.i18n.I18nSupport
    
    import play.api.i18n.MessagesApi 
    

    然后最后添加到您的主索引控制器类

    class Application @Inject()(val messagesApi: MessagesApi) extends
                                               Controller with I18nSupport {
    

    【讨论】:

    • 这个答案主要是复制问题之前答案的部分内容!
    猜你喜欢
    • 2018-01-06
    • 2016-11-08
    • 2016-09-19
    • 2016-12-16
    • 2016-02-22
    • 2017-02-02
    • 2016-01-17
    • 2011-10-17
    • 2016-03-31
    相关资源
    最近更新 更多