首页 > 解决方案 > Java - 将 HTML 参数转换为 JSON

问题描述

我目前正在为一个项目工作,其中数据作为 application/x-www-form-urlencoded 发送到服务器(这很糟糕,它应该是 JSON,但不幸的是我无法更改这个)。

我的问题是,如何将给定的结构转换为 JSON,或者更好的是,将其直接反序列化为对象?

_id=[5bfad95450642c333010daca], 
_rev=[1-9ce33949c3acd85cea6c58467e6a8144], 
type=[Group], 
user=[aUSer], 
default=[aDetail], 
store[aDetail][prop]=[5], 
store[aDetail][lprop1][0][time]=[00:00], 
store[aDetail][lprop1][0][value]=[14], 
store[aDetail][lprop1][0][timeAsSeconds]=[0],
store[aDetail][lprop1][1][time]=[07:00], 
store[aDetail][lprop1][1][value]=[8], 
store[aDetail][lprop1][1][timeAsSeconds]=[25200], 
store[aDetail][anprop]=[25], 
store[aDetail][lprop2][0][time]=[00:00], 
store[aDetail][lprop2][0][value]=[61], 
store[aDetail][lprop2][0][timeAsSeconds]=[0],   
store[bDetail][prop]=[6], 
store[bDetail][lprop1][0][time]=[00:10], 
store[bDetail][lprop1][0][value]=[12], 
store[bDetail][lprop1][0][timeAsSeconds]=[0],
store[bDetail][lprop1][1][time]=[07:10], 
store[bDetail][lprop1][1][value]=[9], 
store[bDetail][lprop1][1][timeAsSeconds]=[25200], 
store[bDetail][anprop]=[25], 
store[bDetail][lprop2][0][time]=[00:00], 
store[bDetail][lprop2][0][value]=[61], 
store[bDetail][lprop2][0][timeAsSeconds]=[0], 
created_at=[2018-01-11T20:48:22.574+0100]

在 json 中,这看起来像这样(跳过大部分已经给定的值):

{
_id: 5bfad95450642c333010daca,
_rev: 1-9ce33949c3acd85cea6c58467e6a8144,
type: Group,
user: aUSer,
default: aDetail,
store: [
  aDetail: {
    prop: 0,
    lprop1: [
      {
        time: 00:00,
        value: 14,
        timeAsSeconds: 0
      }
    ]
  }
]
}   

从这种表单格式到 json 的转换是相当烦人的。任何帮助表示赞赏。顺便说一句,我正在使用 Jackson 和 Java 和/或 Kotlin,如果这有帮助的话。

标签: javahtmljsonformspost

解决方案


我有一个相当幼稚的解决方案,它考虑了嵌套对象和数组。这对我有用,如果在其他环境中使用,可能/将会有一些主要缺点。

解决方案是用 kotlin 编写的,但很可能以不那么复杂的方式编写。

fun parseToMap(map: MutableMap<String, Any>, key: String, value: Any): MutableMap<String, Any> {
    val cleanedV = if (value is String) URLDecoder.decode(value, "UTF-8") else value

    if (!key.contains("[")) {
        map.putIfAbsent(key, cleanedV)
    } else {
        // mapKey is the key going to get stored in the map
        val mapKey = key.substring(0, key.indexOf("["))

        // nextKey is the next key pushed to the next call of parseToMap
        var nextKey = key.removePrefix(mapKey)
        nextKey = nextKey.replaceFirst("[", "").replaceFirst("]", "")

        var isArray = false
        var index = -1

        if (nextKey.contains("[") &&
                nextKey.substring(0, nextKey.indexOf("[")).matches(Regex("[0-9]+"))) {
            index = nextKey.substring(0, nextKey.indexOf("[")).toInt()
            isArray = true
        }

        // mapkey used for object in list
        val newMapKey = if (isArray) nextKey.substring(nextKey.indexOf("[") + 1, nextKey.indexOf("]")) else ""

        val child: Any?
        var childMap: MutableMap<String, Any> = mutableMapOf()

        if (map.containsKey(mapKey)) {
            println("key $mapKey exists already")
            child = map[mapKey]

            when (child) {
                is MutableList<*> -> {
                    if (child == null || child.isEmpty()) {
                        childMap = mutableMapOf()
                        val tmpList = child as MutableList<Any>
                        tmpList.add(childMap)
                        map.put(newMapKey, tmpList)
                    } else {
                        if (child.size > index) {
                            childMap = child.get(index) as MutableMap<String, Any>
                            childMap = parseToMap(childMap, newMapKey, value)
                        } else {
                            childMap = parseToMap(childMap, newMapKey, value)
                            val tmpList = child as MutableList<Any>
                            tmpList.add(childMap)
                        }
                    }
                }
                is MutableMap<*, *> -> childMap = map.get(mapKey) as MutableMap<String, Any>
            }
        } else {
            if (isArray) {
                child = mutableListOf<Any>()
                childMap = parseToMap(childMap, newMapKey, value)
                child.add(childMap)
                map.put(mapKey, child)
            } else {
                childMap = mutableMapOf<String, Any>()
            }
        }

        if (!isArray) parseToMap(childMap, nextKey, value)

        map.putIfAbsent(mapKey, childMap)
    }

    return map
}

应该使用 Map 和每个参数键(就像我的问题中已经提到的那样)以及每个参数的值来调用此方法。


推荐阅读