我观察到,当我向 Play Framework Form-class 添加超过 18 个参数时,我得到了一个很长的(对我来说难以理解的)编译错误。
这是记录在案的限制吗?我需要在表单帖子中接收多达 29 个参数。当我从开放标准实现协议时,我不会决定参数的设计和数量。
我是这样映射的:
val registration = Form(mapping(
"client_type" -> nonEmptyText,
"client_id" -> optional(nonEmptyText),
... up to 29 args, all optional(nonEmptyText)
){ (clientType, clientId ...) => RegistrationRequest(clientType, clientId ...) }
{ req => None })
我的策略是以这种方式进行映射,而不是应用/取消应用并创建案例类的层次结构。原因是要解决 Case 类中的 22 个参数限制,这是我遇到的第一个看似任意的限制。最多 18 个 args 映射工作,之后我得到一个很长的编译错误。
可以在此处找到错误消息(太长而无法包含):https ://gist.github.com/2928297
我正在寻找有关如何解决此限制的建议。我知道在 Post 表单中发送 29 个参数是不好的设计,但它仍然应该是可能的。
破解/解决方法/解决方案
好的,这是我一起破解的解决方法(写这篇文章比实施花费的时间要长得多,我破解了大约 30 分钟)
我编写了预处理请求参数并添加组前缀以对某些参数进行分组的函数。然后我使用生成的 Map[String, String] 并继续处理表单类,像往常一样进行验证等。这允许我在映射中使用嵌套案例类并低于 18 个参数限制。
当心:前面有丑陋的代码!我可能不应该展示这样的早期 hacky 代码,但我希望它能帮助其他想要解决方法的人。
def preprocessFormParams(prefix:String, replace:String)(implicit request:Request[AnyContent]):Map[String, String] = request.body.asFormUrlEncoded.map( _.filterKeys( _.startsWith(prefix)).map( m => m._1.patch(0, replace, prefix.length) -> m._2.head )).getOrElse(Map.empty)
def unprocessedFormParams(prefixes:Set[String])(implicit request:Request[AnyContent]):Map[String, String] = request.body.asFormUrlEncoded.map( _.filterKeys( !prefixes.contains(_) ).map( m => m._1 -> m._2.head )).getOrElse(Map.empty)
所以这些函数可能应该用于理解或拆分,但这里是:preprocessedFormParms 接受一个前缀并替换它:
val clientParams = preprocessFormParams("client_", "client.")
("client_id" -> "val1", "client_type" -> "val2") becomes ("client.id" -> "val1", "client.type" -> "val2")
当我有 group.key1, group.key2 形式的参数时,我可以像这样嵌套案例类
Form(mapping("client" -> mapping("type" -> nonEmptyText
"id" -> optional(nonEmptyText),
"secret" -> optional(nonEmptyText))
(RegisterClient.apply)(RegisterClient.unapply)
... more params ...)
(RegisterRequest.apply)(RegisterRequest.unapply)
在我的行动中,我继续过滤掉我的每个组
implicit request =>
val clientParams = preprocessFormParams("client_", "client.")
val applicationParams = preprocessFormParams("application_", "application.")
val unprocessedParams = unprocessedFormParams(Set("client_", "application_"))
val processedForm = clientParams ++ applicationParams ++ unprocessedParams
最后,我可以像平常一样应用我的表单,但现在我得到了嵌套结构,它减少了参数的数量,并希望使案例类更易于管理。
clientRegistrationForm.bind(processedForm).fold( ... )
使用这种方法,您可以减少参数的数量。如果您的参数没有像我的问题那样易于分组的相同前缀,那么您仍然可以使用相同的基本方法,但可以根据其他标准进行过滤。