【问题标题】:Play framework handling session state播放框架处理会话状态
【发布时间】:2013-12-25 12:34:53
【问题描述】:

我有一个基于 Play 框架和 Scala 构建的 Web 应用程序。它是关于向用户呈现一组问题,每个问题都有一组答案。有些问题有单选按钮类型的答案,有些问题有复选框作为答案。当用户单击开始测试时,我调用控制器,获取问题列表及其答案并将结果作为案例类返回到视图模板。我现在需要在用户回答每个问题时保持测试状态。他可以上一个,下一个,我需要跟踪他回答的所有问题。

来自 Java EE 背景,我认为我可以将案例类存储在会话中并在我的控制器中对其进行操作。但不幸的是,这看起来不像,因为 Play 框架的会话是一个键值对字符串,字符串,而不是字符串,对象。我现在被我的应用卡住了,由于我对 Play 框架的经验有限,我想寻求建议。

【问题讨论】:

    标签: scala session playframework-2.1


    【解决方案1】:

    Play 框架中根本没有状态,所以如果你想在多个 HTTP 请求中保留一些数据,可以方便地使用 Session 范围,它实际上创建带有键/值对(字符串、字符串)的 cookie,并且它们限制为 4KB大小。

    我的建议是使用 Json,Play-json 库很棒。如果您有带有 JSON Read/Write/Format 组合器的模型而不是简单的模型。

    Ok(render(Questions)).withSession("answers" -> Json.prettyPrint(Json.toJson(Answer)))
    

    读取会话值可以这样完成:

    def index = Action { implicit request =>
          session.get("answers").map { answers =>
            val jsValueAnswers: JsValue = Json.parse(answers)
            val answersModel: YourAnswerModel = Json.fromJson(jsValueAnswers) 
            Ok("Got previous answers and created session cookie with them")
            .withSession("answers2" -> Json.prettyPrint(Json.toJson(answersModel)))
          }
        }
    

    希望这对您有所帮助。

    干杯

    【讨论】:

    • 问题是我需要将整个测试存储在会话中,而不仅仅是用户看到的当前问题的答案。用户看到的问题有一组答案,他将选择一个并提交给服务器。然后,我应该接受他对该问题的回答,并针对该问题更新我的 Test 对象。我只是想知道如何利用 Json 来做到这一点。您能否详细说明一下,因为我存储将要呈现的问题的当前答案是不够的!
    • 一切都取决于对象的模型,您可以为对象编写自己的读/写/格式或使用宏启动。 case class Answer(id:Long, value:String) case class TestObject(id: Long, List(Answers)) 隐式val answerRead = Json.readHow to Answerimplicit val answerWrite = Json.writeHow to Answer
    • 把前面的评论弄得一团糟 :) 我是新来的 :) 所以,在你的情况下,将会话值从字符串转换为 json 而不是每次 POST/GET 上的对象并更新值不是很好的解决方案 imo 所以我建议你采纳 James 的建议并使用 memcached。
    【解决方案2】:

    Play 仅支持会话字符串,因为它将所有会话状态存储在 cookie 中 - 这意味着 Play 节点无需任何类型的集群/状态共享技术即可扩展。

    如果您要存储的数据很小(小于 2k),那么只需将其序列化为 JSON,或者在您的情况下,更简单的方法是将其序列化为逗号分隔的答案列表。

    否则,您可以将其存储在memcached或redis等缓存中。

    【讨论】:

    • memcached 是一种数据库吗?我从来没有用过它。从它的名称来看,它看起来像是一种缓存,我可以使用它来存储模仿会话的键、值对并将我的对象存储在那里。是不是为了这个目的。我将在这方面进行探索。
    【解决方案3】:

    Play 是一个设计为无状态的框架,因此您找不到任何关于服务器端会话的具体概念。当然,这并不是严格禁止的,如果您需要它,在这种情况下,您可以使用服务器端技术(缓存或数据库)作为您的项目的容器和用于存储访问密钥字符串的 Play-cookie 会话。

    这是一个使用 Play Cache 存储对象的示例:

    import play.api.cache.Cache
    import play.api.Play.current
    
    val key = UUID.randomUUID.toString
    Cache.set(key, yourModel, 0)
    Ok.withSession("answer_key" -> key)
    

    这是一个检索示例:

    import play.api.cache.Cache
    import play.api.Play.current
    
    val key = session.get("answer_key").getOrElse("none")
    val yourModel = Cache.getAs[ModelClass](key).getOrElse(//whatever you want if not exists)
    

    【讨论】:

    • 缓存方法的问题在于,即使指定了对象在缓存中的超时时间,也不能保证数据会在那里。所以我不想相信缓存。
    • 我不认为这是一个真正的问题。 Play 使用EHCache 作为默认实现,它实现了一个永久磁盘存储,在虚拟机重启之间存储数据。您在 JEE Web 会话中的类似行为。使用 cookie,您的序列化数据限制为 4 Kb,不使用缓存。
    • 为什么你认为这不是一个真正的问题? Play 缓存机制背后的想法是检索频繁请求的对象,而不是作为会话的替代品。看一下链接:playframework.com/documentation/2.0.3/JavaCache 第一段说缓存中的数据可能会丢失!正因为如此,我不想相信它。
    • 我认为在你的情况下这不是一个真正的问题。但我理解你的论点,你可以使用数据库和缓存进行优化。当然作为 cookie 的替代品(cookie 不适合作为数据容器)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-28
    • 1970-01-01
    • 2015-01-19
    • 1970-01-01
    • 2014-10-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多