tangguo

播放框架2.0:将值存储在Http.Context中

spring

我正在尝试在play框架的scalaquery中实现“基于请求”的会话。我使用scalaquery创建了一个会话,并尝试将其存储在当前的http上下文中,如下所示:

def withTransaction[A](bp: BodyParser[A])(f: Request[A] => Result): Action[A] = {
   Action(bp) {
     request =>
       val context = Http.Context.current()
       val session = createSession()
       session.conn.setAutoCommit(false)
       context.args.put("scalaquery.session", session)
       try {
         val result = f(request)
         session.conn.commit()
         result
       }
       catch {
         case t: Throwable =>
           session.conn.rollback()
           throw t
       }
       finally {
         session.close()
         context.args.remove("scalaquery.session")
       }
   }
}

然后将动作包装在控制器中,例如:

withTransaction(parse.anyContent) {
    Action {
       //code that produces a result here
    }
}

但是,它在以下行中崩溃:

val context = Http.Context.current() 
[RuntimeException: There is no HTTP Context available from here.] 

那么,为什么上下文不可用?该代码直接由框架调用,因此不应在执行该代码时设置上下文吗?还是我使用错误的方式访问上下文?

编辑:“会话”的类型为org.scalaquery.session.Session。我之所以要在HttpContext中进行设置,是为了使被包装的操作可以以“ http作用域”的方式访问它,即每个请求分别存储其会话,而所有需要会话的服务都可以在公共位置找到它。每个请求分隔的范围。


阅读 321

收藏
2020-11-17

共1个答案

小编典典

我认为问题是您在Scala控制器中使用Java API。Http.Context仅在使用Java控制器时设置。您是否考虑过使用Scala Session API?

另外,另一个问题是,为什么您需要在上下文中存储会话?我想您还是将其最后删除了。如果您需要子操作能够访问会话,则可以在函数中传递它。

我只是假设session是类型Session

def withTransaction[A](bp: BodyParser[A])(f: Session => Request[A] => Result): Action[A] = {
   Action(bp) {
     request =>
       val session = createSession()
       session.conn.setAutoCommit(false)
       try {
         val result = f(session)(request)
         session.conn.commit()
         result
       }
       catch {
         case t: Throwable =>
           session.conn.rollback()
           throw t
       }
       finally {
         session.close()
       }
   }
}

而您的子操作将是

withTransaction(parse.anyContent) { session => request =>
    //code that produces a result here
}

您无需再将其包装Action,因为它已经被包装withTransaction

2020-11-17