Play/Scala/Anorm 保存对可变数量问题的答案

Play/Scala/Anorm saving answer to variable number of questions

我正在使用带有 anorm/pgsql 的游戏框架来创建一个调查应用程序。问题的回复以 JSONB 格式保存,因为某些回复具有嵌套的回复类型。我可以通过 POST'ing 保存到我的 routes.conf 文件中定义的路由来保存对单个问题的响应,但是我无法思考我将如何创建逻辑来接受逻辑几个问题一次。基本上,当单击调查中的 'Next' 按钮时,将发布 2-n 个问题的答案。我有如下代码,但目前不确定如何使用 POST:

对其进行测试
  def jsonSaveMany(userResponses:List[Response],email:String,id:Long) = {
    DB.withConnection{
      implicit c =>
       for (response <- userResponses) jsonSave(response,response.useremail,response.id)

    }
  }
  def jsonSave(usersResponse:Response,email:String,id:Long) = {
    DB.withConnection{
      implicit c =>
        val userResponse=usersResponse.response
        val userJson:String = s"""{"response":"$userResponse"}"""
        val pgObject = new PGobject();
        pgObject.setType("jsonb")
        pgObject.setValue(userJson)
        SQL(s"INSERT INTO responses(response,useremail,questionid) values ({userResp},{eMail},{quesId})")
          .on('userResp -> anorm.Object(pgObject), 'eMail -> s"$email",'quesId -> id)
          .executeInsert(SqlParser.scalar[String].singleOpt)
    }
  }

我一直在使用 Twirl 模板引擎测试的视图文件采用 @(responseForm: Form[Response]) 参数,但基本上我需要能够为其提供一个 Form[Response] 类型的列表,其中列表的范围可以是2-n 个问题。我似乎想不出更好的方法来表达这个,甚至无法测试这个逻辑是否有效。我不确定如何在我用来测试的 scala.html 文件中创建表单 [Response] 列表。

我最近一直在尝试的另一种方法是在响应案例 class 的伴随对象中使用 JSON inception,如下所示:implicit val responseReads = Json.reads[Response] 但我无法测试发布通过 CURL 对此进行处理,因为当我 POST 到我为此功能定义的路由时,我没有得到任何响应。

我的问题基本上是,我如何利用地图类型的函数获取每个问题并将响应保存到数据库并通过简单的前端 GUI 或终端的基本 CURL 对其进行测试?

最终我放弃了 jsonSaveMany() 函数并在 ResponseController 文件而不是我的 DBController 文件中进行了理解。

为了有效地测试这一点,我使用了 ws.URL Future 调用,它直接调用了我自己的 API 端点。这样我就可以简单地通过 scala.html 页面中的一个简单的 link 进行身份验证和测试,该页面 post 编辑了一个 JSON 对象的虚拟序列来测试它们是否 post编辑成功。我的单元测试是这样的:

def postJSONTest = SecuredAction {
    request =>
      val datum1 = Json.obj(
        "questionid" -> 14,
        "id" -> 14,
        "response" -> "godzilla"
      )

      val datum2 = Json.obj(
        "questionid" -> 15,
        "id" -> 15,
        "response" -> "van halen"
      )

      val data = JsArray(Seq(datum1,datum2))
      val email = request.identity.email.get
      val url = s"http://localhost:9000/response/save/$email"
      val futureResponse: Future[WSResponse] = ws.url(url).post(data)
      Redirect(routes.ResponseController.responses).flashing("success" -> "JSON posted!")
  }

我正在为 authentication/authorization 使用 silhouette,并且 request.identity.email.get 检索当前登录用户的电子邮件。

当我将数据附加到数据时,它呈现为 json 数组,如下所示:

[{"questionid":14,"id":14,"response":"godzilla"},{"questionid":15,"id":15,"response":"van halen"}]

我的响应案例 class 包含一个隐含的 json reader,如下所示:

case class Response (questionid:Long,
                     id:Long,
                     response:String)


object Response {
  /**
   * the implicit reader responseReads converts incoming JSON with
   * keys equal to the property names of the Response case class
   * into a format that is easily saved to pgSQL
   */
  implicit val responseReads=Json.reads[Response]

我的 ResponseController.scala 文件中的函数包含一个 for-comprehension,它使用隐式 JSON 读取方法将 JSON 对象数组中的每个元素转换为 Response 对象。这使它成为一种可以轻松保存到 pgSQL 中的格式。

  def postResponse(email:String) = Action {
    implicit request =>
        val json = request.body.asJson.get
        val jsonList = json.as[List[JsObject]]
        for (item <- jsonList) {
            val oneItem = item.as[Response]
            Response.jsonSave(oneItem,email)
            }
        Ok("success")
  }

这是我的一般方法,真正帮助我的部分是直接在我的应用程序中使用 Future[WSResponse] = ws.url(url).post(data) 到 post JSON 数据。我尝试使用 CURL 和 chrome 扩展 POSTMAN,但在使用这些方法时遇到了问题。希望这个答案可以帮助其他人使用 play/scala.