2016-02-25 77 views
1

我想在Spray路由不區分大小寫的情況下進行參數解析。例如:噴霧路由中的大小寫不敏感參數解析

​​

在這條路徑中,我希望pageSize和appId參數在不區分大小寫的情況下工作。例如,pagesize = 5或PAGESIZE = 5。

+3

您可以創建一個自定義指令來代替參數。我現在不在計算機上,但通過查看參數的實現不應該很難。 –

回答

1

看起來像從URI邏輯獲取查詢參數在ParamDefMagnet2.filter函數中硬編碼。

爲了克服這個限制,我會複製該代碼,用ctx.request.uri.query.find(_._1.equalsIgnoreCase(paramName))代替邏輯並在需要時導入它。

使用例子是這樣的:

import CaseInsensitiveQueryParameters._ 

val route: Route = { 
    (path("search") & get) { 
    parameters('pagesize.as[Int] ?, 'appId ?) { (pageSize, appId) => 
     ... 
    } 
    } 
} 

而改變implicits應該是這樣的:

object CaseInsensitiveQueryParameters { 
    type ParamDefMagnetAux[A, B] = ParamDefMagnet2[A] { type Out = B } 
    def ParamDefMagnetAux[A, B](f: A ⇒ B) = new ParamDefMagnet2[A] { type Out = B; def apply(value: A) = f(value) } 

    import spray.httpx.unmarshalling.{ FromStringOptionDeserializer ⇒ FSOD, _ } 
    import BasicDirectives._ 
    import RouteDirectives._ 

    /************ "regular" parameter extraction ******************/ 

    private def extractParameter[A, B](f: A ⇒ Directive1[B]) = ParamDefMagnetAux[A, Directive1[B]](f) 
    private def filter[T](paramName: String, fsod: FSOD[T]): Directive1[T] = 
    extract(ctx ⇒ fsod(ctx.request.uri.query.find(_._1.equalsIgnoreCase(paramName)))).flatMap { 
     case Right(x)        ⇒ provide(x) 
     case Left(ContentExpected)    ⇒ reject(MissingQueryParamRejection(paramName)) 
     case Left(MalformedContent(error, cause)) ⇒ reject(MalformedQueryParamRejection(paramName, error, cause)) 
     case Left(x: UnsupportedContentType)  ⇒ throw new IllegalStateException(x.toString) 
    } 
    implicit def forString(implicit fsod: FSOD[String]) = extractParameter[String, String] { string ⇒ 
    filter(string, fsod) 
    } 
    implicit def forSymbol(implicit fsod: FSOD[String]) = extractParameter[Symbol, String] { symbol ⇒ 
    filter(symbol.name, fsod) 
    } 
    implicit def forNDesR[T] = extractParameter[NameDeserializerReceptacle[T], T] { nr ⇒ 
    filter(nr.name, nr.deserializer) 
    } 
    implicit def forNDefR[T](implicit fsod: FSOD[T]) = extractParameter[NameDefaultReceptacle[T], T] { nr ⇒ 
    filter(nr.name, fsod.withDefaultValue(nr.default)) 
    } 
    implicit def forNDesDefR[T] = extractParameter[NameDeserializerDefaultReceptacle[T], T] { nr ⇒ 
    filter(nr.name, nr.deserializer.withDefaultValue(nr.default)) 
    } 
    implicit def forNR[T](implicit fsod: FSOD[T]) = extractParameter[NameReceptacle[T], T] { nr ⇒ 
    filter(nr.name, fsod) 
    } 
} 
2

我把穆斯塔法的回答一步,擴展參數語法,所以你可以使用非-case敏感參數連同區分大小寫(Big Hooray for typeclasses和magnet pattern!):

package caseinsensitive 

import spray.routing.SimpleRoutingApp 
import akka.actor.ActorSystem 
import spray.routing.directives.BasicDirectives 
import spray.routing.directives.RouteDirectives 
import scala.language.implicitConversions 

/**/ 

import spray.httpx.unmarshalling.{ FromStringOptionDeserializer ⇒ FSOD, _} 

trait ToCINameReceptaclePimps { 
    implicit def symbol2CINR(symbol: Symbol) = new CINameReceptacleHelper[String](symbol.name) 
    implicit def string2CINR(string: String) = new CINameReceptacleHelper[String](string) 
} 


case class CINameReceptacleHelper[T](name: String) { 
    def insensitive = CINameReceptacle[T](name) 
} 

case class CINameReceptacle[A](name: String) { 
    def as[B] = CINameReceptacle[B](name) 
    def as[B](deserializer: FSOD[B]) = CINameDeserializerReceptacle(name, deserializer) 
    def ? = as[Option[A]] 
    def ?[B](default: B) =CINameDefaultReceptacle(name, default) 
    def ![B](requiredValue: B) = CIRequiredValueReceptacle(name, requiredValue) 
} 

case class CINameDeserializerReceptacle[A](name: String, deserializer: FSOD[A]) { 
    def ? = CINameDeserializerReceptacle(name, Deserializer.liftToTargetOption(deserializer)) 
    def ?(default: A) = CINameDeserializerDefaultReceptacle(name, deserializer, default) 
    def !(requiredValue: A) = CIRequiredValueDeserializerReceptacle(name, deserializer, requiredValue) 
} 

case class CINameDefaultReceptacle[A](name: String, default: A) 

case class CIRequiredValueReceptacle[A](name: String, requiredValue: A) 

case class CINameDeserializerDefaultReceptacle[A](name: String, deserializer: FSOD[A], default: A) 

case class CIRequiredValueDeserializerReceptacle[A](name: String, deserializer: FSOD[A], requiredValue: A) 



/**/ 

trait CaseInsensitiveParams extends ToCINameReceptaclePimps { 

    import spray.routing._ 
    import spray.routing.directives._ 
    import spray.httpx.unmarshalling.{ FromStringOptionDeserializer ⇒ FSOD, _ } 
    import BasicDirectives._ 
    import RouteDirectives._ 




    type ParamDefMagnetAux[A, B] = ParamDefMagnet2[A] { type Out = B } 
    def ParamDefMagnetAux[A, B](f: A ⇒ B) = new ParamDefMagnet2[A] { type Out = B; def apply(value: A) = f(value) } 

    private def extractParameter[A, B](f: A ⇒ Directive1[B]) = ParamDefMagnetAux[A, Directive1[B]](f) 

    private def filterCI[T](paramName: String, fsod: FSOD[T]): Directive1[T] = 
    extract(ctx ⇒ fsod(ctx.request.uri.query.find(_._1.equalsIgnoreCase(paramName)).map(_._2))).flatMap { 
     case Right(x)        ⇒ provide(x) 
     case Left(ContentExpected)    ⇒ reject(MissingQueryParamRejection(paramName)) 
     case Left(MalformedContent(error, cause)) ⇒ reject(MalformedQueryParamRejection(paramName, error, cause)) 
     case Left(x: UnsupportedContentType)  ⇒ throw new IllegalStateException(x.toString) 
    } 


    /************ "regular" parameter extraction ******************/ 

    implicit def forCINDesR[T] = extractParameter[CINameDeserializerReceptacle[T], T] { nr ⇒ 
    filterCI(nr.name, nr.deserializer) 
    } 
    implicit def forCINDefR[T](implicit fsod: FSOD[T]) = extractParameter[CINameDefaultReceptacle[T], T] { nr ⇒ 
    filterCI(nr.name, fsod.withDefaultValue(nr.default)) 
    } 
    implicit def forCINDesDefR[T] = extractParameter[CINameDeserializerDefaultReceptacle[T], T] { nr ⇒ 
    filterCI(nr.name, nr.deserializer.withDefaultValue(nr.default)) 
    } 
    implicit def forCINR[T](implicit fsod: FSOD[T]) = extractParameter[CINameReceptacle[T], T] { nr ⇒ 
    filterCI(nr.name, fsod) 
    } 

    /************ required parameter support ******************/ 

    private def requiredFilterCI(paramName: String, fsod: FSOD[_], requiredValue: Any): Directive0 = 
    extract(ctx ⇒ fsod(ctx.request.uri.query.find(_._1.equalsIgnoreCase(paramName)).map(_._2))).flatMap { 
     case Right(value) if value == requiredValue ⇒ pass 
     case _          ⇒ reject 
    } 

    implicit def forCIRVR[T](implicit fsod: FSOD[T]) = ParamDefMagnetAux[CIRequiredValueReceptacle[T], Directive0] { rvr ⇒ 
    requiredFilterCI(rvr.name, fsod, rvr.requiredValue) 
    } 
    implicit def forCIRVDR[T] = ParamDefMagnetAux[CIRequiredValueDeserializerReceptacle[T], Directive0] { rvr ⇒ 
    requiredFilterCI(rvr.name, rvr.deserializer, rvr.requiredValue) 
    } 




} 




object Main extends App with SimpleRoutingApp with CaseInsensitiveParams { 
    implicit val system = ActorSystem("my-system") 

    startServer(interface = "localhost", port = 8080) { 
    path("hello") { 
     parameters("foo".insensitive.?) { foo => 
     get { 
      complete { 
      <h1>You said {foo} </h1> 
      } 
     } 
     } 
    } 
    } 
} 

如果您不需要所有這些,則可以使用parameterMap指令並從中獲取參數。