2019独角兽企业重金招聘Python工程师标准>>>
第一次见GraphQL的时候是去年,完全被惊呆了,心想这么牛逼,前台想要什么就可以拿到什么数据,不想要的完全可以不获取,之后就开始尝试使用GraphQL,然后发现入门失败。
但是自己又有这方面的需求,比如有一个数据格式(暂定用户信息),有多个接口需要获取它的信息,而且每个接口的需求不一样,也可能后端为了限制某些字段不给某个接口返回。
例如:用户(id,姓名,年龄,爱好,出生日期,身份证,密码,头像)
A接口:只需要(姓名、年龄、爱好),其他信息无权限获取
B接口:需要(姓名、出生日期、身份证、头像),其他信息并不关心,且密码无法获取
C接口:有权限获取全部信息,但又不需要全部信息
当遇到这种情况的时候基础的json可以较方便的解决,但是如果遇到联级的信息呢??
比如:国家(名称,地区(名称,市(名称,县....)))这样联级的信息,就难搞了。
因此需要GraphQL这样的工具,直接写一个字符串去过滤出需要的数据({country{name,Area{name,city{name,county}}}})只通过这个字符串就过滤出我们需要的json数据。
下面进入代码阶段(完整的代码在最后面贴出来)
开发语言:Kotlin
开发平台:Windows
开发工具:Idea
完整代码:https://gitee.com/houkunlin/goour-utils/blob/master/src/main/kotlin/cn/goour/kotlin/tools/MapTools.kt
第一步:写一个字符串解析方法,解析过滤字符串,解析成map键值对形式,key为字段信息,value为子类嵌套过滤字符串
private fun getKeyMap(key: String): HashMap {val keyMap = hashMapOf()var lastIndex = 0var endIndex = 0var left = 0key.forEachIndexed { index, c ->when (c) {',' -> {if (left == 0 && lastIndex {if (left == 0) {endIndex = index}++left}'}' -> {if (--left == 0) {keyMap[key.substring(lastIndex, endIndex).replace(",", "")] = key.substring(endIndex + 1, index)lastIndex = index + 2}}}if (index == key.lastIndex && lastIndex }
第二步:就是开始对bean的字段进行过滤了,返回一个map,key为字段信息,value为字段值
fun Any.toMapInclude(key: String): Map {val keyMap &#61; getKeyMap(key)val fields &#61; this.javaClass.declaredFieldsval map &#61; hashMapOf()fields.forEach {it.isAccessible &#61; trueif (keyMap.contains(it.name) && it.name !&#61; "Companion") {val value &#61; keyMap[it.name]if (value !&#61; null) {val obj &#61; it.get(this)when {Iterable::class.java.isInstance(obj) -> {val list &#61; arrayListOf()obj as Collection<*>obj.forEach {if (it !&#61; null) {list &#43;&#61; it.toMapInclude(value)}}map[it.name] &#61; list}it.type.isArray -> {val list &#61; arrayListOf()obj as Array<*>obj.forEach {if (it !&#61; null) {list &#43;&#61; it.toMapInclude(value)}}map[it.name] &#61; list}else -> map[it.name] &#61; obj.toMapInclude(value)}} else {val obj &#61; it.get(this)when {it.type.isArray -> {obj as Array<*>map[it.name] &#61; obj.toList()}else -> map[it.name] &#61; it.get(this)}}}}return map
}
OK&#xff0c;完工&#xff0c;之后开始测试跑一下
fun main(args: Array) {val g &#61; Country(name &#61; "中国",area &#61; Area(name &#61; "广西", gps &#61; arrayOf("1.x", "2.x"),city &#61; City(name &#61; "桂林",county &#61; listOf(County(name &#61; "测试县城1", gps &#61; arrayOf("1.x", "2.x")),County(name &#61; "测试县城2", gps &#61; arrayOf("11.x", "22.x"))))))val str &#61; "name,area{name,gps,city{name,county{name}}}"println(g.toMapInclude(str))//{area&#61;{city&#61;{name&#61;桂林, county&#61;[{name&#61;测试县城1}, {name&#61;测试县城2}]}, name&#61;广西, gps&#61;[1.x, 2.x]}, name&#61;中国}println(g.toMapInclude(str).toJsonString())//{"area":{"city":{"name":"桂林","county":[{"name":"测试县城1"},{"name":"测试县城2"}]},"name":"广西","gps":["1.x","2.x"]},"name":"中国"}
}
下面贴另一份测试结果
fun main(args: Array) {val g &#61; Country(name &#61; "中国",area &#61; Area(name &#61; "广西", gps &#61; arrayOf("1.x", "2.x"),city &#61; City(name &#61; "桂林",county &#61; listOf(County(name &#61; "测试县城1", gps &#61; arrayOf("1.x", "2.x")),County(name &#61; "测试县城2", gps &#61; arrayOf("11.x", "22.x"))))))val str &#61; "name,area{name,gps,city{name,county{name}}}"println(g.toMapInclude(str))println(g.toMapInclude(str).toJsonString())var start &#61; System.currentTimeMillis()for (i in 1..100000) {g.toMap()}var end &#61; System.currentTimeMillis()println("转map耗时&#xff1a;${(end - start) / 1000.0}s")start &#61; System.currentTimeMillis()for (i in 1..100000) {g.toMapInclude(str)}end &#61; System.currentTimeMillis()println("过滤耗时&#xff1a;${(end - start) / 1000.0}s")start &#61; System.currentTimeMillis()for (i in 1..100000) {JSONObject.toJSON(g)}end &#61; System.currentTimeMillis()println("json耗时&#xff1a;${(end - start) / 1000.0}s")start &#61; System.currentTimeMillis()for (i in 1..100000) {g.toMapInclude(str).toJsonString()}end &#61; System.currentTimeMillis()println("转map转json耗时&#xff1a;${(end - start) / 1000.0}s")
}
/*
运行结果
电脑处理器&#xff1a;AMD A12-9700P 2.50GHz
内存RAM&#xff1a;8.00GB&#xff08;7.46GB可用&#xff09;
{area&#61;{city&#61;{name&#61;桂林, county&#61;[{name&#61;测试县城1}, {name&#61;测试县城2}]}, name&#61;广西, gps&#61;[1.x, 2.x]}, name&#61;中国}
{"area":{"city":{"name":"桂林","county":[{"name":"测试县城1"},{"name":"测试县城2"}]},"name":"广西","gps":["1.x","2.x"]},"name":"中国"}
转map耗时&#xff1a;0.097s
过滤耗时&#xff1a;1.213s
json耗时&#xff1a;1.092s
转map转json耗时&#xff1a;2.074s
*/
下面贴全部完整的代码
package cn.goour.kotlin.toolsimport com.alibaba.fastjson.JSONObjectfun Any.toMap(): Map {val fields &#61; this.javaClass.declaredFieldsval map &#61; hashMapOf()fields.forEach {it.isAccessible &#61; trueif (it.name !&#61; "Companion") {map[it.name] &#61; it.get(this)}
// println(it.name &#43; " " &#43; it.type.name &#43; " " &#43; it.get(this))}return map
}private fun getKeyMap(key: String): HashMap {
// println(key)val keyMap &#61; hashMapOf()var lastIndex &#61; 0var endIndex &#61; 0var left &#61; 0key.forEachIndexed { index, c ->// println("$index &#61; $c")when (c) {&#39;,&#39; -> {if (left &#61;&#61; 0 && lastIndex // println("$lastIndex -- $endIndex")
// println("${key.substring(lastIndex, endIndex)} -- null")keyMap[key.substring(lastIndex, endIndex).replace(",", "")] &#61; nulllastIndex &#61; index &#43; 1}}&#39;{&#39; -> {if (left &#61;&#61; 0) {endIndex &#61; index}&#43;&#43;left}&#39;}&#39; -> {if (--left &#61;&#61; 0) {
// println("$lastIndex -- $endIndex -- $index")
// println("${key.substring(lastIndex, endIndex)} -- ${key.substring(endIndex &#43; 1, index)}")keyMap[key.substring(lastIndex, endIndex).replace(",", "")] &#61; key.substring(endIndex &#43; 1, index)lastIndex &#61; index &#43; 2}}}if (index &#61;&#61; key.lastIndex && lastIndex // println("$lastIndex -- $endIndex")
// println("${key.substring(lastIndex)} -- null")keyMap[key.substring(lastIndex).replace(",", "")] &#61; null}}return keyMap
}fun Any.toMapInclude(key: String): Map {
// println(key)val keyMap &#61; getKeyMap(key)val fields &#61; this.javaClass.declaredFieldsval map &#61; hashMapOf()fields.forEach {it.isAccessible &#61; trueif (keyMap.contains(it.name) && it.name !&#61; "Companion") {val value &#61; keyMap[it.name]if (value !&#61; null) {val obj &#61; it.get(this)when {Iterable::class.java.isInstance(obj) -> {val list &#61; arrayListOf()obj as Collection<*>obj.forEach {if (it !&#61; null) {list &#43;&#61; it.toMapInclude(value)}}map[it.name] &#61; list}it.type.isArray -> {val list &#61; arrayListOf()obj as Array<*>obj.forEach {if (it !&#61; null) {list &#43;&#61; it.toMapInclude(value)}}map[it.name] &#61; list}else -> map[it.name] &#61; obj.toMapInclude(value)}} else {val obj &#61; it.get(this)when {it.type.isArray -> {obj as Array<*>map[it.name] &#61; obj.toList()}else -> map[it.name] &#61; it.get(this)}}}}return map
}fun Map<*, *>.toJsonString(dateFormat: String &#61; "yyyy-MM-dd HH:mm:ss"): String {return JSONObject.toJSONStringWithDateFormat(this, dateFormat)
}fun main(args: Array) {val g &#61; Country(name &#61; "中国",area &#61; Area(name &#61; "广西", gps &#61; arrayOf("1.x", "2.x"),city &#61; City(name &#61; "桂林",county &#61; listOf(County(name &#61; "测试县城1", gps &#61; arrayOf("1.x", "2.x")),County(name &#61; "测试县城2", gps &#61; arrayOf("11.x", "22.x"))))))val str &#61; "name,area{name,gps,city{name,county{name}}}"println(g.toMapInclude(str))println(g.toMapInclude(str).toJsonString())var start &#61; System.currentTimeMillis()for (i in 1..100000) {g.toMap()}var end &#61; System.currentTimeMillis()println("转map耗时&#xff1a;${(end - start) / 1000.0}s")start &#61; System.currentTimeMillis()for (i in 1..100000) {g.toMapInclude(str)}end &#61; System.currentTimeMillis()println("过滤耗时&#xff1a;${(end - start) / 1000.0}s")start &#61; System.currentTimeMillis()for (i in 1..100000) {JSONObject.toJSON(g)}end &#61; System.currentTimeMillis()println("json耗时&#xff1a;${(end - start) / 1000.0}s")start &#61; System.currentTimeMillis()for (i in 1..100000) {g.toMapInclude(str).toJsonString()}end &#61; System.currentTimeMillis()println("转map转json耗时&#xff1a;${(end - start) / 1000.0}s")
}data class Country(var name: String,var area: Area? &#61; null
)data class Area(var name: String,var gps: Array? &#61; null,var city: City? &#61; null
)data class City(var name: String,var county: List
)data class County(var name: String,var gps: Array? &#61; null
)