在Spring Boot中将JSON对象作为响应返回

iwe*_*esi 54 java json spring-boot

我在Spring启动时有一个示例Rest Controller:

@RestController
@RequestMapping("/api")
class MyRestController
{

    @GetMapping(path = "/hello")
    public JSONObject sayHello()
    {
        return new JSONObject("{'aa':'bb'}");
    }


}
Run Code Online (Sandbox Code Playgroud)

我正在使用json库:org.json

当我点击api /你好时,我得到一个异常说:

servlet [dispatcherServlet]的Servlet.service()与path []的上下文引发了异常[请求处理失败; 嵌套异常是java.lang.IllegalArgumentException:没有为根本原因找到类型为:class org.json.JSONObject的返回值的转换器

java.lang.IllegalArgumentException:找不到类型为:class org.json.JSONObject的返回值的转换器

问题是什么 有人可以解释究竟发生了什么.我是SpringBoot的新手.

提前致谢 :)

pre*_*mar 64

当您使用spring boot web时,jackson依赖是隐式的,我们不必明确定义.如果使用eclipse,您可以在依赖关系层次结构选项卡中检查pom.xml中的jackson依赖项.

而且,由于您已注释,pom.xml因此无需进行显式json转换.只需返回一个POJO和jackson序列化器将负责转换为json.它等同于@RestController与@Controller 一起使用时的使用.我们不是放置@ResponseBody每个控制器方法而是放置@ResponseBody而不是vanilla @RestController,@Controller默认情况下应用于该控制器中的所有资源.
请参考此链接: https ://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-responsebody

您遇到的问题是因为返回的对象(JSONObject)没有某些属性的getter.并且您的目的不是序列化此JSONObject,而是序列化POJO.所以只需返回POJO.
请参阅此链接: https ://stackoverflow.com/a/35822500/5039001

如果要返回json序列化字符串,则只返回字符串.在这种情况下,Spring将使用StringHttpMessageConverter而不是JSON转换器.

  • 如果要返回一组没有严格编译时结构的名称 - 值对,可以返回`Map <String,Object>`或`Properties`对象 (5认同)

g00*_*00b 35

您当前的方法不起作用的原因是因为默认情况下使用Jackson来序列化和反序列化对象.但是,它不知道如何序列化JSONObject.如果要创建动态JSON结构,可以使用a Map,例如:

@GetMapping
public Map<String, String> sayHello() {
    HashMap<String, String> map = new HashMap<>();
    map.put("key", "value");
    map.put("foo", "bar");
    map.put("aa", "bb");
    return map;
}
Run Code Online (Sandbox Code Playgroud)

这将导致以下JSON响应:

{ "key": "value", "foo": "bar", "aa": "bb" }
Run Code Online (Sandbox Code Playgroud)

这有点受限,因为添加子对象可能会变得有点困难.杰克逊有自己的机制,使用ObjectNodeArrayNode.要使用它,您必须ObjectMapper在服务/控制器中自动装配.然后你可以使用:

@GetMapping
public ObjectNode sayHello() {
    ObjectNode objectNode = mapper.createObjectNode();
    objectNode.put("key", "value");
    objectNode.put("foo", "bar");
    objectNode.put("number", 42);
    return objectNode;
}
Run Code Online (Sandbox Code Playgroud)

此方法允许您添加子对象,数组和使用所有各种类型.

  • 这里的映射器是什么? (2认同)
  • 知道必须付出如此大的努力才能生成有意义的 JSON 对象,这真是“令人震惊”!同样令人遗憾的是,Pivotal 根本没有做出任何努力(https://spring.io/guides/gs/actuator-service/)来指出这些限制。幸运的是,我们有这样的!;) (2认同)

San*_*ose 32

您可以String按照@vagaasen的建议返回响应,也可以使用ResponseEntitySpring提供的Object,如下所示.通过这种方式,您还可以返回Http status code哪个在webservice调用中更有帮助.

@RestController
@RequestMapping("/api")
public class MyRestController
{

    @GetMapping(path = "/hello", produces=MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<Object> sayHello()
    {
         //Get data from service layer into entityList.

        List<JSONObject> entities = new ArrayList<JSONObject>();
        for (Entity n : entityList) {
            JSONObject entity = new JSONObject();
            entity.put("aa", "bb");
            entities.add(entity);
        }
        return new ResponseEntity<Object>(entities, HttpStatus.OK);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果我在实体中添加 JSONObject,它再次给我类似的异常 (2认同)
  • +1 建议使用 MediaType.APPLICATION_JSON_VALUE,因为它确保生成的结果被解析为 json 而不是 xml,如果您没有定义,可能会发生这种情况 (2认同)

max*_*mus 8

你也可以使用hashmap

@GetMapping
public HashMap<String, Object> get() {
    HashMap<String, Object> map = new HashMap<>();
    map.put("key1", "value1");
    map.put("results", somePOJO);
    return map;
}
Run Code Online (Sandbox Code Playgroud)


Ale*_*hko 8

更正确的为 API 查询创建 DTO,例如 entityDTO:

  1. 实体列表的默认响应 OK:
@GetMapping(produces=MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(HttpStatus.OK)
public List<EntityDto> getAll() {
    return entityService.getAllEntities();
}
Run Code Online (Sandbox Code Playgroud)

但是如果你需要返回不同的 Map 参数,你可以使用接下来的两个例子
2. 返回一个像 map 这样的参数:

@GetMapping(produces=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> getOneParameterMap() {
    return ResponseEntity.status(HttpStatus.CREATED).body(
            Collections.singletonMap("key", "value"));
}
Run Code Online (Sandbox Code Playgroud)
  1. 如果您需要返回某些参数的映射(自 Java 9 起):
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> getSomeParameters() {
    return ResponseEntity.status(HttpStatus.OK).body(Map.of(
            "key-1", "value-1",
            "key-2", "value-2",
            "key-3", "value-3"));
}
Run Code Online (Sandbox Code Playgroud)


Dmi*_*try 6

@RequestMapping("/api/status")
public Map doSomething()
{
    return Collections.singletonMap("status", myService.doSomething());
}
Run Code Online (Sandbox Code Playgroud)

附注。仅适用于 1 个值


Ash*_*win 6

如果您需要使用字符串返回 JSON 对象,那么以下应该可以工作:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.ResponseEntity;
...

@RestController
@RequestMapping("/student")
public class StudentController {

    @GetMapping
    @RequestMapping("/")
    public ResponseEntity<JsonNode> get() throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode json = mapper.readTree("{\"id\": \"132\", \"name\": \"Alice\"}");
        return ResponseEntity.ok(json);
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)