Returning JSON object as response in Spring Boot

我在 Spring 引导中有一个 RestController 示例:

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

我使用的是 JSON 库 org.json

当我点击 API /hello时,我得到一个异常:

Service ()用于具有路径的上下文中的 servlet [ patcherServlet ] 抛出异常[请求处理失败; 嵌套异常为 异常: 找不到返回的转换器 具有根原因的类 org.json.JSONObject ]的值

异常: 找不到返回的转换器 值类型: 类 org.json.JSONObject

有什么问题? 谁能解释一下到底发生了什么?

536783 次浏览

当前方法无法工作的原因是,在默认情况下 Jackson 用于序列化和反序列化对象。但是,它不知道如何序列化 JSONObject。如果希望创建动态 JSON 结构,可以使用 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;
}

这将导致以下 JSON 响应:

{ "key": "value", "foo": "bar", "aa": "bb" }

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

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

这种方法允许您添加子对象、数组和使用所有各种类型。

您可以像@vasaasen 建议的那样返回一个响应 String,也可以像下面这样使用 Spring 提供的 ResponseEntity Object。通过这种方式,你也可以返回 Http status code,这是更有帮助的网络服务调用。

@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);
}
}

当你使用 SpringBootweb 时,Jackson 依赖是隐式的,我们不需要显式定义。如果使用 eclipse,您可以在依赖层次选项卡的 pom.xml中检查 Jackson 依赖性。

正如您使用 @RestController注释的那样,不需要进行显式的 json 转换。只需返回一个 POJO 并且 Jackson 序列化程序将负责转换到 json。它相当于在与@Controller 一起使用时使用 @ResponseBody。我们没有将 @ResponseBody放在每个控制器方法上,而是将 @RestController而不是普通的 @Controller放在控制器中,而且默认情况下,@ResponseBody应用于该控制器中的所有资源。Https://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-responsebody

您面临的问题是因为返回的对象(JSONObject)没有针对某些属性的 getter。您的目的不是序列化这个 JSONObject,而是序列化一个 POJO。那就把 POJO 还回去。
参考这个链接: < a href = “ https://stackoverflow. com/a/35822500/5039001”> https://stackoverflow.com/a/35822500/5039001

如果您想返回一个 json 序列化的字符串,那么只需返回该字符串。在这种情况下,Spring 将使用 StringHttpMessageConverter 而不是 JSON 转换器。

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

PS。只对1值有效

也可以使用散列表

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

使用 ResponseEntity<ResponseBean>

在这里,您可以根据自己的喜好使用 ResponseBean 或任何 java bean 来返回 api 响应,这是最佳实践。我使用 Enum 作为响应。它将返回 API 的状态代码和状态消息。

@GetMapping(path = "/login")
public ResponseEntity<ServiceStatus> restApiExample(HttpServletRequest request,
HttpServletResponse response) {
String username = request.getParameter("username");
String password = request.getParameter("password");


loginService.login(username, password, request);
return new ResponseEntity<ServiceStatus>(ServiceStatus.LOGIN_SUCCESS,
HttpStatus.ACCEPTED);
}

用于响应 ServiceStatus 或(ResponseBody)

    public enum ServiceStatus {


LOGIN_SUCCESS(0, "Login success"),


private final int id;
private final String message;


//Enum constructor
ServiceStatus(int id, String message) {
this.id = id;
this.message = message;
}


public int getId() {
return id;
}


public String getMessage() {
return message;
}
}

SpringRESTAPI 的响应应该是以下键

  1. 状态码
  2. 信息

你会得到下面的最终答复

{


"StatusCode" : "0",


"Message":"Login success"


}

您可以根据需要使用 ResponseBody (javaPOJO、 ENUM 等)。

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

  1. 默认响应对实体列表没有问题:
@GetMapping(produces=MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(HttpStatus.OK)
public List<EntityDto> getAll() {
return entityService.getAllEntities();
}

但是如果需要返回不同的 Map 参数,可以使用下面两个示例
2. 返回一个参数,如 map:

@GetMapping(produces=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> getOneParameterMap() {
return ResponseEntity.status(HttpStatus.CREATED).body(
Collections.singletonMap("key", "value"));
}
  1. 如果您需要某些参数的返回映射(自 Java9以来) :
@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"));
}

如果您需要使用 String 返回一个 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);
}
...
}

我使用 org.json.JSONObject 的 toMap ()方法在 Controller 中返回 Map < String,Object > ,如下所示。

@GetMapping("/json")
public Map<String, Object> getJsonOutput() {
JSONObject jsonObject = new JSONObject();
//construct jsonObject here
return jsonObject.toMap();
}

你可以这样做:

@RestController
@RequestMapping("/api")
class MyRestController
{
@GetMapping(path = "/hello")
public JSONObject sayHello()
{
return new JSONObject("{'aa':'bb'}").toMap();;
}
}