在 PlayFramework、scala、reactivemongo 应用程序中使用来自 MongoDB 的数据填写 HTML 表单时得到 None.get

getting None.get when filling an HTML form from data from MongoDB in PlayFramework, scala, reactivemongo application

我正在学习 ReactiveMongo。在我的应用程序中,我想从 MongoDB 中检索数据并将其填写在 HTML 表单中。

早些时候我的问题是代码没有编译。我修复了它,但现在我得到的是 None.get 而不是数据库中的值。

我在 MongoDB 中的数据将映射到以下情况 class

case class User2(
                  name:String,
                  email:String,
                  age:Int,
                  gender:Boolean
                )

以下是 Reactive Mongo 要求的 reader。

问题 1 - 我从 MongoDB

得到 None.get 而不是值
object User2{
    implicit object UserReader extends BSONDocumentReader[User2] {
      def read(doc: BSONDocument): User2= {
        val name = doc.getAs[String]("name").get
        val email = doc.getAs[String]("email").get
        val age = doc.getAs[Int]("age").get
        val gender = doc.getAs[Boolean]("gender").get

        User2(name, email, age, gender)
      }
    }
  }

以下是我的控制器代码。忽略不必要的导入

package controllers

import anorm.{NotAssigned, Pk}
import play.api.data.Form
import play.api.data.Form._
import play.api.data.Forms
import play.api.mvc.Controller
import play.api.mvc._
import play.api.data.Forms._
import play.api.data.validation.Constraints._
import play.api.db.DB
import models._
import scala.concurrent._
import ExecutionContext.Implicits.global
import scala.util.Try


import reactivemongo.api.MongoDriver
import reactivemongo.bson._
import reactivemongo.api.MongoConnection
import reactivemongo.api.collections.default.BSONCollection



object Application_Test extends Controller {
  val user2Form: Form[User2] = Form(
    mapping(
      "name" -> nonEmptyText,
      "email" -> email,
      "age" -> number,
      "gender" -> boolean
    )(User2.apply)(User2.unapply)
  )

  def index = Action {
    Async {
      val driver = new MongoDriver()
      val connection = driver.connection(List("localhost"))
      val db = connection.db("website-users")
      val collection = db.collection[BSONCollection]("user-table")

      val query = BSONDocument("name" -> "Manu")

      val result = collection.find(query).cursor[User2].collect[List]()
/*    
          result.map { user =>
      //following code doesn't compile. I think result is List[models.User2]. I tried using user and user(0) but none of them compile
            Ok(views.html.HTMLTest(user2Form.fill(user)))
          }
*/

// this version of code compiles

result.map { user => user match {
        case List() => Ok(views.html.HTMLTest(user2Form.fill(User2("a","a@a.com",1,true))))
        case h::v => Ok (views.html.HTMLTest (user2Form.fill (h) ) )
      }
      }
    }
  }
}

以下是HTML

问题 2 - @form("name").value 是从表单中提取值的正确方法吗?

@(form:Form[User2])

<!DOCTYPE html>
<html lang="en" xmlns:font-variant="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-COMPATIBLE" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>HTML Test</title>
    <link rel="stylesheet" type="text/css" href="@routes.Assets.at("stylesheets/bootstrap.min.css")">
    <!--link rel="stylesheet" href="stylesheets/bootstrap-theme.min.css"-->
    <style type="text/css">

        html, body{height:100%; margin:0;padding:0}

.center-form {
  width:100%;
  margin:auto;
  position:relative;
  top:50%;
  transform: translateY(-50%)
}


</style>

</head>
<body>

<div class="container center-form" >

    <!-- for medium and large screens,
    First row of Bootstrap grid contains logo. Total 3 columns (12/4). Logo in middle column-->

    <div class="row" >
        <!--empty column-->
        <div class="col-md-4 col-lg-4" ></div>

        <!--logo column-->
        <div class="col-md-4 col-lg-4" >
            <div>
                <img src="@routes.Assets.at("images/Logo303x64.png")" alt="SalesWorkspace Logo" height="64" width="303">
            </div>
        </div>
        <!--empty column-->
        <div class="col-md-4 col-lg-4"></div>
        </div>

    <!-- for medium and large screens,
    Second row of Bootstrap grid contains the form for username and password. Total 3 columns (12/4). -->
        <div class="row" >
            <!--empty column-->
            <div class="col-md-4 col-lg-4"></div>

            <!--form-->
            <div class="col-md-4 col-lg-4">

            <form>
                    <div class="form-group">
                        <label for="first-name">First Name</label>
                        <input type="text" class="form-control" id="first-name" value="@form("name").value" required>
                    </div>

                    <div class="form-group">
                        <label for="last-name">Last Name</label>
                        <input type="text" class="form-control" id="last-name" value="@form("name").value" required>
                    </div>

                    <div class="form-group">
                        <label for="email">Email</label>
                        <input type="email" class="form-control" id="email" value="@form("email").value" required>
                    </div>
                    <div class="form-group">
                        <label for="password">Password</label>
                        <input type="password" class="form-control" id="password" required>
                    </div>
                    <div class="form-group">
                        <label for="confirm-password">Password</label>
                        <input type="password" class="form-control" id="confirm-password" required>
                    </div>


                    <button type="submit" class="btn btn-primary">Login</button>
                </form>
            </div>
            <!--empty column-->
            <div class="col-md-4 col-lg-4"></div>
        </div>
</div>
<!--script src="@routes.Assets.at("javascripts/jquery-1.9.0.min")"></script-->
<!--script src="@routes.Assets.at("javascripts/bootstrap.min.js")"></script-->
</body>
</html>

如 API 文档中所述,BSONDocument.getAs[T] returns 和 Option[T] 等可用于可选文档字段。

应用.get 这样Option 显然是一种代码味道。

如果你想获得一个被假定为必填的字段,你最好使用 .getAsTry,它会在出错时提供详细信息(比 NoSuchElementException 来自 [=17] 更有帮助=]).

def read(doc: BSONDocument): User2= (for {
    name <- doc.getAsTry[String]("name")
    email <- doc.getAsTry[String]("email")
    age <- doc.getAsTry[Int]("age")
    gender <- doc.getAsTry[Boolean]("gender")
  } yield User2(name, email, age, gender)).get