1

我需要检查每个请求是否存在 YMD uri 日期参数,如果存在,请将其存储在请求中,以便以后访问应用程序的各个部分,其中隐式请求可用。

请求拦截似乎是一个明显的选择: https ://github.com/playframework/Play20/wiki/ScalaInterceptors

但是,我没有看到添加到请求的方法(实际上RequestHeader是可用的),假设它是只读/不可变的。

我可以通过Action Composition向 Request 添加数据;但是,这种方法仅限于组合动作,而不是每个动作(为什么我希望上述全局 Before Interceptor 方法能够以某种方式工作)。例如,经过身份验证的操作包装器允许我将登录用户的 id 存储在请求中。

trait Secured { 
  private case class Success[A](uid: Int, r: Request[A]) extends WrappedRequest(r)

  def Authenticated[A](p: BodyParser[A])
    (f: Success[A] => Result)(implicit group: RoleGroup) = {

    def apply(maybeUser: Option[String])(implicit r: Request[A]) = {
      maybeUser map {id =>
        Cache.orElse(group.to_s+"-"+id, 3600){
          repo.user.get(id.int, group) map(_.active) getOrElse false
      } fold ( onFail, f(Success(id.int, r)) )
    }
  }

我想对可能的 uri 日期参数执行相同的操作,但将其应用于所有操作,或者再次在通过全局拦截器触发播放路由机制之前应用它。

非常感谢的想法,谢谢

4

1 回答 1

0

要模拟向请求中注入任意数据,您可以扩展 WrappedRequest:

case class Outcome[A](
  r: Request[A], 
  uid: Int, 
  startDate: String,
  endDate: String,
  uriDate: JodaTime) extends WrappedRequest(r)

然后创建返回自定义请求包装器实例的操作提供程序特征。例如,基本任务操作可能如下所示:

trait TaskRequest 
  extends DateParser {

  def Task[A](p: BodyParser[A])(f: Outcome[A] => Result) = {
    Action(p) { implicit r =>
      f( toOutcome[A](r, r.session.get("userID").map(_.toInt) getOrElse 0) )
    }
  }
  def Task(f: Outcome[AnyContent] => Result): Action[AnyContent] = {
    import play.api.mvc.BodyParsers._
    Task(parse.anyContent)(f)
  }

  protected def toOutcome[A](r: Request[A], uid: Int) = {
    val(start,uriDate) = (startDate(r), toDate(r.uri))
    val end = seasonEnd(start)
    Outcome(r, uid, start.toString("yyyyMMdd"), end.toString("yyyyMMdd"), uriDate)
  }

  val ymdMatcher = "\\d{8}".r  
  protected def startDate(uri: String) = {
    ymdMatcher.findFirstIn(uri). // set season start based on ymd URI param if exist 
    map(_.startDate) getOrElse seasonStart(new JodaTime)
  }

  protected def toDate(uri: String) =
    ymdMatcher.findFirstIn(r.uri).map(_.to_date) getOrElse new JodaTime
}

然后从 Task 派生一个 Authenticated 动作:

trait Secured
  extends TaskRequest { 

  def Authenticated[A](p: BodyParser[A])
    (f: Outcome[A] => Result)(implicit group: RoleGroup) = {

    def apply(maybeUser: Option[String])(implicit r: Request[A]) = {
      maybeUser map {id =>
        Cache.orElse(group.to_s+"-"+id, 3600){
          repo.user.get(id.int, group) map(_.active) getOrElse false
      } fold ( onFail, f( toOutcome(r, id.int)) )
    }
  }

然后在您的控制器中使用:

def index = Authenticated { implicit request=>
  // voila, current season start date since no uri date param exist
  request.startDate
}

当然,我可以在每个操作的基础上调用日期操作函数,但这仅适用于 Action scope。如何访问模板层中的 startDate?我不能,但是使用自定义请求包装器,您可以注入任何您想要的内容,并轻松地在任何地方引用数据。因此,不要将 play 的请求纳入范围:

@(model: Foo, title: String)(implicit request: play.api.mvc.Request[_])

您引用您的自定义请求包装器:

@(model: Foo, title: String)(implicit request: controllers.Outcome[_])

这项工作做得很好,全局拦截我还没有找到用途(也许重新路由一些遗留的 URI,但没有像 WrappedRequest 方法那样强大)

于 2012-11-02T08:26:06.123 回答