1. 程式人生 > >AKKA HTTP查詢結果返回JSON字串

AKKA HTTP查詢結果返回JSON字串

akka http有一個json模組專門用於處理json和scala型別之間的轉換,通常介面以json格式作為結果響應格式,如果使用此功能,在專案的配置中引入json包,gradle引入如下:

compile 'com.typesafe.akka:akka-http-spray-json_2.12:10.1.3'

如果是maven構建專案,則是:

<dependency>
  <groupId>com.typesafe.akka</groupId>
  <artifactId>akka-http-spray-json_2.12</artifactId>
  <version>10.1.4</version>
</dependency>

json和Map型別之間可以很好的轉換,其他型別也可以:

  • Byte, Short, Int, Long, Float, Double, Char, Unit, Boolean
  • String, Symbol
  • BigInt, BigDecimal
  • Option, Either, Tuple1 - Tuple7
  • List, Array
  • immutable.{Map, Iterable, Seq, IndexedSeq, LinearSeq, Set, Vector}
  • collection.{Iterable, Seq, IndexedSeq, LinearSeq, Set}
  • JsValue

需要注意的是,對於Map型別,如上標紅所示,只是針對immutable型別而言。如果你需要對mutable的Map做json響應轉換,可以先將其轉為immutable Map(map.toMap即可)即可。

如何將scala型別的Map轉為json字串?

1.定義響應的資料模型

首先明確需要響應的資料模型是什麼,比如如果是key,value型別的資料,則Map物件即可,如果是複雜的可進行巢狀,如:

final case class Items(items:Map[String, List[Map[String,String]]])//一個複雜的響應結果資料模型,注意均是不可變的型別

2.定義json隱式變數

implicit val itemsFormat = jsonFormat1(Items)//定義json格式化隱式變數

3.返回資料模型物件

在業務邏輯處理完後,返回定義的資料模型物件後,使用

complete(item.items)

即可返回json字串,從響應的報文中可看出:Content-Type: application/json,已將響應頭自動設定為json格式。

具體核心程式碼如下:

route部分:

final case class SensorsModel(keys:Map[String,String],conditions:Map[String,String]) 
implicit val sensorsModelFormat = jsonFormat2(SensorsModel)
    val route = post {
      path("user") {
        entity(as[SensorsModel]) { model =>//這裡的SensorsModel類是自定義的請求引數接受模型,如上,可按實際情況自定義
          val startkey = model.keys.get("startkey") match {
            case Some(item) => item
            case _ => ""
          }
          val endkey = model.keys.get("endkey") match {
            case Some(item) => item
            case _ => ""
          }
          val result: Future[Option[Items]] = selectByRangeKey(startkey,endkey,model.conditions)
          onSuccess(result) {
            case Some(item) => complete(item.items)
            case None => complete(StatusCodes.NotFound)
          }
        }
      }
    }

查詢hbase邏輯程式碼部分:

def selectByRangeKey(startkey: String, endkey: String, conds:Map[String, String]): Future[Option[Items]] = {
    val conn = HBaseConnection.getHBaseConn()
    val tbl = conn.getTable(TableName.valueOf("xxxxx"))
    val scan = new Scan()
    scan.setStartRow(Bytes.toBytes(startkey))
    scan.setStopRow(Bytes.toBytes(endkey))
    scan.setCaching(10000)
    val filterList = new FilterList()
    if(conds.size>0){
      for ((k, v) <- conds) {
        filterList.addFilter(new SingleColumnValueFilter(Bytes.toBytes("data"), Bytes.toBytes(k), CompareOp.EQUAL, Bytes
          .toBytes(v)))
      }
      scan.setFilter(filterList)
    }
    val rs = tbl.getScanner(scan).iterator()
    var items:mutable.Map[String, List[Map[String,String]]] = new mutable.HashMap[String, List[Map[String,String]]]
    var list = new ListBuffer[Map[String,String]]()
    try {
      while (rs.hasNext) {
        var map = new mutable.HashMap[String,String]()
        val cells = rs.next()
        for (cell: Cell <- cells.rawCells()) {
          val qf = Bytes.toString(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength())
          val value = Bytes.toString(cell.getValueArray, cell.getValueOffset, cell.getValueLength)
          map.put(qf,value)
          println("qf:"+qf+",value:"+value)
        }
        list+=map.toMap
      }
      items.put("result",list.toList)
    } finally {
      tbl.close()
      conn.close()
    }
    val resultOption: Option[Items] = Some(new Items(items.toMap))
    logInfo("Query Result:" + Some(items))
    Future {
      resultOption
    }
  }

還可以在程式碼中拼接json字串,結果響應時可指定響應內容為json:

complete(HttpEntity(ContentTypes.`application/json`,jsonResultString))

測試結果:

Text中的請求內容是:{"keys":{"startkey": "1001 ","endkey": "1003 "},"conditions":{}} 

響應結果如下: