代码之家  ›  专栏  ›  技术社区  ›  coder25

akka http使用json支持和xmlsupport

  •  6
  • coder25  · 技术社区  · 8 年前

    我希望在部门为“HR”时以XML格式打印数据,而在部门为“Tech”时以JSON格式打印数据。

    我们能用吗 喷雾JSON载体 https://doc.akka.io/docs/akka-http/current/common/json-support.html 和XML支持 https://doc.akka.io/docs/akka-http/current/common/xml-support.html 在一起

     private[rest] def route =
      (pathPrefix("employee") & get) {
        path(Segment) { id =>
          parameters('department ? "") { (flag) =>
            extractUri { uri =>
              complete {
                flag match {
                  case "hr": =>  {
    
                HttpEntity(MediaTypes.`application/xml`.withCharset(HttpCharsets.`UTF-8`),"hr department")
                }
                  case "tech" =>{
                    HttpEntity(ContentType(MediaTypes.`application/json`), mapper.writeValueAsString("tech department"))
    
                  }
    
                }
              }
            }
          }
        }
      }
    

    我尝试的解决方案 我通过使用jsonProtocols和scalaxmlsupport尝试了下面的方法。我得到了预期的编译错误,但找到了部门。

    case class department(name:String)
    private[rest] def route =
      (pathPrefix("employee") & get) {
        path(Segment) { id =>
          parameters('department ? "") { (flag) =>
            extractUri { uri =>
              complete {
                flag match {
                  case "hr": =>  {
    
                complete(department(name =flag))
                }
                  case "tech" =>{
                    complete(department(name =flag))
    
                  }
    
                }
              }
            }
          }
        }
      }
    
    2 回复  |  直到 8 年前
        1
  •  3
  •   SergGr    8 年前

    我认为要达到你想要的目标,你必须克服几个问题:

    1. 您希望根据请求参数自定义响应类型。它意味着标准 implicit -基于封送对您不起作用,您必须执行一些明确的步骤。

    2. 您希望将一些业务对象封送到XML字符串中。不幸的是, ScalaXmlSupport 您引用的不支持这种情况,它只能将XML树封送到响应中。所以您需要一些可以进行XML序列化的库。一种选择是使用 jackson-dataformat-xml 具有 jackson-module-scala . 这也意味着你必须写下你自己的习惯 Marshaller . 幸运的是,这并不难。

    下面是一些可能适用于您的简单代码:

    import akka.http.scaladsl.marshalling.{ToResponseMarshallable, Marshaller}
    
    // json marshalling
    import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
    import spray.json._
    import spray.json.DefaultJsonProtocol._
    implicit val departmentFormat = DefaultJsonProtocol.jsonFormat1(department)
    val departmentJsonMarshaller = SprayJsonSupport.sprayJsonMarshaller[department]
    
    // xml marshalling, need to write a custom Marshaller
    // there are several MediaTypes for XML such as `application/xml` and `text/xml`, you'll have to choose the one you need.
    val departmentXmlMarshaller = Marshaller.StringMarshaller.wrap(MediaTypes.`application/xml`)((d: department) => {
      import com.fasterxml.jackson.dataformat.xml.XmlMapper
      import com.fasterxml.jackson.module.scala.DefaultScalaModule
      val mapper = new XmlMapper()
      mapper.registerModule(DefaultScalaModule)
      mapper.writeValueAsString(d)
    })
    
    
    private val route =
      (pathPrefix("employee") & get) {
        path(Segment) { id =>
          parameters('department ? "") { (flag) =>
            extractUri { uri => {
              flag match {
                case "hr" => {
                  // explicitly use the XML marshaller 
                  complete(ToResponseMarshallable(department(name = flag))(departmentXmlMarshaller))
                }
                case "tech" => {
                  // explicitly use the JSON marshaller 
                  complete(ToResponseMarshallable(department(name = flag))(departmentJsonMarshaller))
                }
              }
            }
            }
          }
        }
      }
    

    请注意,为了使Jackson XML序列化程序正确工作, department 类应该是顶级类,否则您会得到一个关于错误根名称的神秘错误。

        2
  •  1
  •   kag0    8 年前

    Akka HTTP已经内置了内容类型协商。理想情况下,您应该使用这个方法,让一个marshaller知道如何将您的部门转换为XML或JSON,并让客户机设置 Accept 标题。

    不过,听起来可能你不能让你的客户这样做,所以这里是你可以做的,假设你已经 ToEntityMarshaller[department] 对于XML和JSON,使用 ScalaXmlSupport SprayJsonSupport .

    val toXmlEntityMarshaller: ToEntityMarshaller[department] = ???
    val toJsonEntityMarshaller: ToEntityMarshaller[department] = ???
    implicit val departmentMarshaller = Marshaller.oneOf(toJsonEntityMarshaller, toXmlEntityMarshaller)
    
    def route =
      parameters("department") { departmentName =>
        // capture the Accept header in case the client did request one
        optionalHeaderValueByType[Accept] { maybeAcceptHeader => 
          mapRequest ( _
            .removeHeader(Accept.name)
            // set the Accept header based on the department
            .addHeader(maybeAcceptHeader.getOrElse(
              Accept(departmentName match {
                case "hr" ⇒ MediaTypes.`application/xml`
                case "tech" ⇒ MediaTypes.`application/json`
              })
            ))
          ) (
            // none of our logic code is concerned with the response type
            complete(department(departmentName))
            )
        }
      }
    
    推荐文章