我正在忙着将我们的Spring / Groovy应用程序之一迁移到Spray / Scala。我对Spray很新,所以如果这是一个初学者问题,请原谅我。
目标是模拟我们的日志记录拦截器,它记录每个请求/响应的各种数据。在这部分代码中有很多逻辑,所以它不是一个简单的日志行。另外,我想用这个逻辑包装所有请求。
现有的Groovy / Spring拦截器:
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler {
//do some logging logic
}
void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
//do some more logging logic
}
我的Scala演员看起来像这样
class BootServiceActor extends Actor with ViewingController with LazyLogging with ViewingWire {
def actorRefFactory = context
implicit val ctx = context.dispatcher
def receive = runRoute(route)(exceptionHandler, RejectionHandler.Default, context,
RoutingSettings.default, LoggingContext.fromActorRefFactory)
}
答案 0 :(得分:5)
Spray / Scala的一大卖点是你可以避免“魔法”,拦截器等无形的东西。您可以通过使用类型和/或指令来实现相同的功能,但是您所做的一切在代码中都可见,并且由于类型系统,因此可以重构。例如。您可以使用scalaz Writer
来累积与特定请求关联的日志消息,然后为具有现有编组的任何Marshaller[Writer[MyLogStructure, A]]
定义提供A
的“元编组器”,以及以正确的结构编写了该特定请求的所有日志。如果您愿意,我很乐意详细介绍这种方法。
“预处理”部分最好由简单的Directive
处理;因为Spray是反应性的和异步的,所以并不存在配对“前后”处理的概念。相反,您对请求执行某些操作并将其交给下一个处理步骤,最终将发送响应。如果你需要将一些“上下文”从预处理传递到后句柄,那么可能最好用“上下文类型”(我试图避免说出可怕的m字),如{{1 }}
答案 1 :(得分:1)
解决方案我是根据lmm的输入实现的
我最终制定了一个自定义指令,其中包含以下内容:
trait LoggingDirectives {
val logger = LoggerFactory.getLogger(classOf[LoggingDirective])
import spray.routing.directives.BasicDirectives._
def logResponseInfo(user : String): Directive0 =
mapRouteResponse { response ⇒
//...
logger.info("RESPONSE >> "+user+":"+response)
response
}
def logRequestInfo: Directive0 =
mapRequest { request ⇒
//...
logger.info("REQUEST << " + request);
request
}
}
然后我把它包裹在我的路线上:
val route = logRequestInfo {
accountAuthenicationValidator { profileId:String =>
logResponseInfo(profileId) {
controllerRoute(profileId)
}
}
}
其中accountAuthenicationValidator是另一个自定义指令,controllerRoute是处理所有路径的核心路径,是(String =&gt; Route)