0

在我的 Spring-boot 控制器中,我有一个返回以下数据结构的端点:

public ResponseEntity<Map<String, Map<String, Object>>> getComplexStructure()

此结构中的内部Object在数据库中保存为原始 JSON 字符串,我不使用我的应用程序中的实际值。目前我必须将该 JSON 反序列化为一个对象,以便我可以从函数中返回它,以便 Spring 可以再次将其序列化为 JSON。这听起来效率低下,我想知道我能否以某种方式跳过 Deserialize Reserialize 部分,只返回 Spring 的原始 JSON 以嵌入到它周围的序列化数据结构中。

现在很明显,如果我像这样返回字符串:

public ResponseEntity<Map<String, Map<String, String>>> getComplexStructure()

JSON解析器会将字符串放在引号中并将其转义,它将只是一个字符串而不是json结构。

是否有一些注释或我可以做些什么来跳过该嵌入式 JSON 的不必要的序列化和反序列化?

读这听起来很简单,如果这个过程有一些好的技术术语,也请提及它们,这将使谷歌搜索更容易:)

4

1 回答 1

1

您可以AbstractHttpMessageConverter针对您的问题使用自定义映射操作。

import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.Map;

@Component
public class CustomMessageConverter extends AbstractHttpMessageConverter<Map<String, Map<String, Object>>> {
    public CustomMessageConverter() {
        super(MediaType.APPLICATION_JSON);
    }

    @Override
    protected boolean supports(Class<?> clazz) {
        return HashMap.class.isAssignableFrom(clazz);
    }

    @Override
    protected Map<String, Map<String, Object>> readInternal(Class<? extends Map<String, Map<String, Object>>> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        return null;
    }

    @Override
    protected void writeInternal(Map<String, Map<String, Object>> value, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        PrintStream printStream = new PrintStream(outputMessage.getBody());

        printStream.print("{");

        // track to put comma between items
        boolean printedEntry = false;

        for (Map.Entry<String, Map<String, Object>> entry : value.entrySet()) {
            /* // if you want to disable null print uncomment it
            if (entry.getValue() == null) {
                continue;
            }
            */
            if (printedEntry) {
                printStream.print(",");
            }

            printStream.print("\"" + entry.getKey() + "\":");
            if (entry.getValue() == null) {
                printStream.print("null");
                continue;
            }

            // INNER ENTRY LOOP
            printStream.print("{");
            // track to put comma between items
            boolean printedInnerEntry = false;
            for (Map.Entry<String, Object> innerEntry : entry.getValue().entrySet()) {
                if (printedInnerEntry) {
                    printStream.print(",");
                }
                printStream.print("\"" + innerEntry.getKey() + "\":");
                printStream.print(innerEntry.getValue());
                printedInnerEntry = true;
            }
            printStream.print("}");

            printedEntry = true;
        }
        printStream.print("}");
    }
}

测试

@RestController
public class HomeController {
    @GetMapping
    public ResponseEntity<Map<String, Map<String, Object>>> getComplexStructure() {
        Map<String, Map<String, Object>> result = new HashMap<>();

        Map<String, Object> innerItem1 = new HashMap<>();
        innerItem1.put("bar1", "{\"item\": 12, \"list\": [1, 2]}");
        innerItem1.put("bar2", "{\"item\": 22, \"test\": \"test@\"}");

        result.put("foo1", innerItem1);

        Map<String, Object> innerItem2 = new HashMap<>();
        innerItem2.put("tail1", "{\"item\": 55}");
        innerItem2.put("tail2", "{\"item\": 77}");

        result.put("foo2", innerItem2);

        return ResponseEntity.ok(result);
    }
}

GET http://localhost:8080/

输出

{"foo1":{"bar1":{"item": 12, "list": [1, 2]},"bar2":{"item": 22, "test": "test@"}},"foo2":{"tail1":{"item": 55},"tail2":{"item": 77}}}

警告

我建议创建一个新类来操作这种特殊情况。因为HashMap是通用的,并且捕获了所有从HashMap. 因此,如果您想更喜欢这种方式,您可以更改以下代码。

创建一个新的返回类型HashMap<String, Map<String, Object>>

public class CustomMessage extends HashMap<String, Map<String, Object>> {
}

用下面的CustomMessageConverter改变supports方法。

@Override
protected boolean supports(Class<?> clazz) {
   return CustomMessage.class.isAssignableFrom(clazz);
}

此外,您可以更改AbstractHttpMessageConverter<CustomMessage>而不是更改,AbstractHttpMessageConverter<Map<String, Map<String, Object>>>但这不是必需的。

使用这个新类更改返回类型。

public ResponseEntity<CustomMessage> getComplexStructure() {
   CustomMessage result = new CustomMessage();
   ...
   return ResponseEntity.ok(result);
}
于 2021-01-08T00:32:07.263 回答