我正在尝试在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作用域”的方式访问它,即每个请求分别存储其会话,而所有需要会话的服务都可以在公共位置找到它。每个请求分隔的范围。
org.scalaquery.session.Session
我认为问题是您在Scala控制器中使用Java API。Http.Context仅在使用Java控制器时设置。您是否考虑过使用Scala Session API?
Http.Context
另外,另一个问题是,为什么您需要在上下文中存储会话?我想您还是将其最后删除了。如果您需要子操作能够访问会话,则可以在函数中传递它。
我只是假设session是类型Session
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
withTransaction