【问题标题】:Scala Play 2.5 How to make Java's Context/Session/Request accessible to a view?Scala Play 2.5 如何使 Java 的 Context/Session/Request 可访问视图?
【发布时间】:2016-12-21 23:06:26
【问题描述】:

我正在开发这个 Scala play-authenticate-usage-scala 项目,我在 Java 框架 play-authenticate 之上构建(我知道,生活并不完美......)。在运行应用程序时,我看到下面包含的异常。

仔细检查堆栈跟踪将我带到使用forProviders.scala.html 模板的视图views._providerPartial.scala.html,而该模板又使用依赖于Java 的Play play.mvc.Http.{ Session, Context, etc} 的类,因此出现错误,因为我的示例应用程序带来了Scala @ 987654326@个。

我知道我可以在 Scala 中做到:

import play.core.j.JavaHelpers

val jContext : play.mvc.Http.Context = JavaHelpers.createJavaContext(request)
val jSession : play.mvc.Http.Session = context.session() 

问题是我怎样才能使上述这些隐含地适用于该视图。

[error] application - 

! @72ef8b5j8 - Internal server error, for (GET) [/login] ->

play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[RuntimeException: There is no HTTP Context available from here.]]
    at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:293)
    at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:220)
    at play.api.GlobalSettings$class.onError(GlobalSettings.scala:160)
    at play.api.DefaultGlobal$.onError(GlobalSettings.scala:188)
    at play.api.http.GlobalSettingsHttpErrorHandler.onServerError(HttpErrorHandler.scala:100)
    at play.core.server.netty.PlayRequestHandler$$anonfun$2$$anonfun$apply$1.applyOrElse(PlayRequestHandler.scala:100)
    at play.core.server.netty.PlayRequestHandler$$anonfun$2$$anonfun$apply$1.applyOrElse(PlayRequestHandler.scala:99)
    at scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:346)
    at scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:345)
    at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
Caused by: java.lang.RuntimeException: There is no HTTP Context available from here.
    at play.mvc.Http$Context.current(Http.java:62)
    at play.mvc.Http$Context$Implicit.session(Http.java:330)
    at com.feth.play.module.pa.views.html.forProviders_Scope0$forProviders$$anonfun$apply$1.apply(forProviders.template.scala:37)
    at com.feth.play.module.pa.views.html.forProviders_Scope0$forProviders$$anonfun$apply$1.apply(forProviders.template.scala:35)
    at play.twirl.api.TemplateMagic$.defining(TemplateMagic.scala:13)
    at com.feth.play.module.pa.views.html.forProviders_Scope0$forProviders.apply(forProviders.template.scala:35)
    at views.html._providerPartial_Scope0$_providerPartial.apply(_providerPartial.template.scala:38)
    at views.html.login_Scope0$login_Scope1$login.apply(login.template.scala:74)
    at controllers.Application$$anonfun$4$$anonfun$apply$4.apply(Application.scala:57)
    at controllers.Application$$anonfun$4$$anonfun$apply$4.apply(Application.scala:57)

更新 我尝试了以下操作,但没有成功。基本上,Java 方面期望所有这些都在ThreadLocal 中。特定的ThreadLocal 实例公开位于play.mvc.Http.Context.current。因此,我准备了一个名为 _adaptScalaToJava.scala.html 的模板助手,如下所示:

@import be.objectify.deadbolt.scala._
@import play.core.j.JavaHelpers

@()(implicit request: AuthenticatedRequest[Any])

@play.mvc.Http.Context.current.set(JavaHelpers.createJavaContext(request))

直接设置当前线程中的jContext,使用方式如下:

@_adaptScalaToJava
@forProviders(playAuth, skipCurrent) { p =>
    <li>
    @if(p.getKey() == "openid") {
        <a href="javascript:void(0);" onclick="askOpenID('@p.getUrl()');">
    } else {
        <a href="@p.getUrl()">
    }
    @_providerIcon(p.getKey())</a>
    </li>
}

但即使编译发现它仍然会触发相同的异常...

【问题讨论】:

    标签: scala playframework play-authenticate


    【解决方案1】:

    在麻烦的代码解决问题之前只放置这一行:

    @play.mvc.Http.Context.current.set(play.core.j.JavaHelpers.createJavaContext(request))
    @forProviders(playAuth, skipCurrent) { p =>
    

    试图让它更干净一点,即它不会一直重置,这对我来说仍然是个谜:为什么这不起作用:

    @if (play.mvc.Http.Context.current.get() == null) { 
        @play.mvc.Http.Context.current.set(play.core.j.JavaHelpers.
             createJavaContext(request)) 
    } 
    

    似乎play.mvc.Http.Context.current 不是null ...底线是我需要连接IDE 并调试代码。

    更新其实这是官方的做法:

    @play.core.j.JavaHelpers.withContext(request) { jContext =>
        @forProviders(playAuth, skipCurrent) { p =>
            ...
        }
    }
    

    【讨论】:

    • 这可能有效,但这不是官方的做法——JavaHelpers 不是 Play 的公共 API 的一部分,可能会在没有警告的情况下更改。
    • 支持 Scala 混合 Java Scala 应用程序的官方方式是什么?就我而言,我想使用 Scala,但没有 Java 插件就无法生存
    • 你应该设置一个 Java 控制器,然后从那里调用 Scala 代码
    • 感谢cmets,真的很有用!我的应用程序处于可以工作的状态,但当然希望它是最好的维护方式......将这些受影响的控制器实现到 Java 中的好主意。现在在玩了一段时间后,我仍然认为应该对混合 Scala-Java 应用程序提供更好、更透明的支持。我更喜欢编写 Scala 比 Java 多 10 倍,并且不应该被任何框架强制使用特定语言。如果 play 有一个通用的基础抽象层和平滑的隐式转换,就不需要play.core.j.JavaHelpers
    • 重构这是 Play 3.0 的主要部分,这也是我提到它的原因。
    猜你喜欢
    • 2013-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多