【问题标题】:Maintaining request parameters across controller and view in Play Framework在 Play Framework 中跨控制器和视图维护请求参数
【发布时间】:2013-10-23 03:08:50
【问题描述】:

我正在使用带有 Java 的 Play Framework,之前没有使用 Scala 的经验。我想要实现的是跨控制器和视图维护请求参数(通常是 GET)。更具体地说,一旦它移交控制权,我需要视图将控制器(通过查询字符串)发送给它的参数传递回控制器。使用表单助手在模板中生成一个表单:

@form(routes.Application.authenticate()) 

我知道我可以使用 play.mvc.Controller.request() 访问当前请求。我需要将表单提交的数据附加到当前查询字符串并通过 URL 全部传递,或者,如果表单方法是 POST,则将当前查询字符串附加到操作 URL 或将参数存储在隐藏字段中并通过 POST 将它们全部传递。

有没有一种简单明了的方法来实现这一点?起初我试图通过一个对象传递所有内容,但后来我遇到了路由器问题,而且我不知道如何将数据传回。

【问题讨论】:

  • 您是否考虑过使用闪存或会话范围?应该会容易得多。
  • 我做到了,我在实现它时遇到了麻烦,发现表单方法更方便。但我可能做错了什么。
  • 我很确定这将是正确的方法。如果您无法弄清楚,请再次检查文档并在闪存范围上发布问题。如果你想让我看看,请 PM 我。您可能还想查看有关该主题的其他帖子:stackoverflow.com/search?q=play+flash+scope

标签: java scala httprequest stateless playframework-2.2


【解决方案1】:

更新

这通常可以通过隐藏的输入字段来完成。根据this的说法,隐藏输入的渲染方式有两种,但我更喜欢最简单的一种:

<input type="hidden" name="hiddenData" value="@data" /> 

在服务器端,您可以从 HashMap filledForm.data().get("hiddenData") 或通过常规数据绑定机制获取数据。 由于您的数据是不确定的,您可以更改输入控件上的名称和值或将 HashMap 作为data 传递。它将像这样呈现:value="{A=B, B=B}" 并且在服务器端您将收到 HashMap。

要通过 GET 发送请求,您需要使用通过 GET 在路由文件中访问的控制器,如下所示:

@helper.form(routes.Application.doLoginGetMethod)

通用表格

Play 框架通常缺少许多重要功能的文档,但至少它在安装文件夹中有示例。 %PLAYINSTALLFODLER%\samples\java\forms 就是你所需要的。

文档在这里:Play framework Forms (Scala)Server side(Java),Templates

无论如何,想法很简单 - 您可以使用相同的表单 API 在客户端和服务器端处理表单。

首先创建 pojo 来存储数据。验证和视觉调优所需的属性:

public static class Login
    @Required
    @Email
    public String email;

    @Required
    @MinLength(5)
    public String password;
 }

第二,你需要创建你的表单——它是无状态的,所以可以重复使用。将其传递给您的视图:

public static final Form<Login> LOGIN_FORM = form(Login.class);
...
public static Result login() {
    return ok(loginView.render(LOGIN_FORM));
}

在您的模板上使用来自views.html.helper 的helpers api 来呈现表单和控件。有很多:checkboxselectoptionstextareaothers

@(loginForm: Form[_])
@import helper._
...
@helper.form(routes.Application.doLogin) { // this differ from original login method

     @if(loginForm.hasGlobalErrors) { // example of validation and form data
         <p class="error">
             @loginForm.globalError.message</span>
         </p>
     }

    @inputText(  // Notice the helper
        loginForm("email"),
        '_showConstraints -> false,
        '_label -> "Your email"
    )

     @inputPassword( // Another helper
         loginForm("password"),
         '_showConstraints -> true,
         '_label -> "Password"
     )
     <input type="submit" value="Login"> // submit button
}

然后在服务器端接收表单:

public static Result doLogin() {
    final Form<Login> filledForm = LOGIN_FORM.bindFromRequest();
// User did not fill everything properly
    if (filledForm.hasErrors()) return badRequest(login.render(filledForm));
return Controller.redirect("Hey!");
}

当然你需要路线:

GET     /login                      controllers.Application.login
POST    /login                      controllers.Application.doLogin

【讨论】:

  • 我已经浏览了文档。我知道如何从模型中生成一个,所以您刚才演示的代码部分已经存在。问题是请求中会有一些不确定的查询参数,我需要视图在提交时连同表单数据一起传回控制器。请注意,参数是不确定的,因此我无法为它们创建模型/POJO 以传递给表单。我只需要在控制器和视图之间的整个通信过程中保留它们。
  • 谢谢,这让事情变得更清楚了,尽管它仍然没有回答我问题的重要部分。假设我想遍历请求中的键值对,从每对中生成一个隐藏的输入,其中 name="key" 和 value="value"。 Scala 的语法是什么?为此,我应该如何使用 Request 对象(通过 play.mvc.Controller.request() 检索)?由于我对 FP 范式不熟悉,我很难弄清楚这一点,而且 Scala 文档对我来说看起来很陈旧。
【解决方案2】:

thisthis 的帮助下,我终于弄清楚了如何生成隐藏输入字段。以下任何一种方法都可以完成这项工作:

@for((key, value) <- request.queryString) {
  <input type="hidden" name="@key" value="@value" />
}

或者:

@request.queryString.map { case (key,value) =>          
  <input type="hidden" name="@key" value="@value" />
}

在 POST 的情况下,@request.queryString 可以简单地替换为 @request.body.asFormUrlEncoded。由于这两种方法都返回Map[String, Seq[String]],因此可能需要展平值(使用@value.mkString);但是,就我而言,代码似乎可以正常工作。我对 Scala 的无知使我无法深入研究幕后发生的事情,但我猜测在每次迭代中,都会返回数组中的第一个元素,就我的应用程序中的 HTTP 请求参数而言,它应该可以工作。如果我曾经用边缘情况对此进行测试,我会更新这篇文章。

【讨论】:

  • 使用此代码,您只需遍历地图并生成 许多 个隐藏输入。您为所有包括可见的请求参数生成隐藏输入,有效地复制它们。根据浏览器和此代码的位置,隐藏参数可能会覆盖用户输入,从而导致不正确的应用行为。从我的角度来看,最好使用单个隐藏输入来存储所有不完善的数据。我在回答中展示了如何生成它。
  • 我通过在生成隐藏输入时排除可见表单输入来解决重复问题。但是你有一点,这不是一个非常干净的解决方案。但是,就像我说的那样,您的回答仍然没有解决我的主要问题。我不能简单地将 request.queryString 作为@data 传递,因为它返回一个 Map (到处都有 String[] 的字符串表示形式不会很有帮助)。我必须使用自定义实用程序方法将 Map 转换为 String 并在服务器端执行相反的操作,这对我来说看起来不是一个更清洁的解决方案。
猜你喜欢
  • 2015-10-27
  • 2011-10-09
  • 1970-01-01
  • 2016-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多