[英]Returning JSON object as response in Spring Boot
I have a sample RestController in Spring Boot:我在 Spring Boot 中有一个示例 RestController:
@RestController
@RequestMapping("/api")
class MyRestController
{
@GetMapping(path = "/hello")
public JSONObject sayHello()
{
return new JSONObject("{'aa':'bb'}");
}
}
I am using the JSON library org.json
我正在使用 JSON 库
org.json
When I hit API /hello
, I get an exception saying :当我点击 API
/hello
时,我得到一个异常说:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed;
Servlet.service() 用于路径 [] 上下文中的 servlet [dispatcherServlet] 引发异常 [请求处理失败; nested exception is java.lang.IllegalArgumentException: No converter found for return value of type: class org.json.JSONObject] with root cause
嵌套异常是 java.lang.IllegalArgumentException: No converter found for return value of type: class org.json.JSONObject] 根本原因
java.lang.IllegalArgumentException: No converter found for return value of type: class org.json.JSONObject
java.lang.IllegalArgumentException:没有找到类型的返回值的转换器:类 org.json.JSONObject
What is the issue?问题是什么? Can someone explain what exactly is happening?
有人可以解释到底发生了什么吗?
As you are using Spring Boot web, Jackson dependency is implicit and we do not have to define explicitly.当您使用 Spring Boot web 时,Jackson 依赖是隐式的,我们不必明确定义。 You can check for Jackson dependency in your
pom.xml
in the dependency hierarchy tab if using eclipse.如果使用 eclipse,您可以在依赖层次结构选项卡中的
pom.xml
中检查 Jackson 依赖项。
And as you have annotated with @RestController
there is no need to do explicit json conversion.并且由于您已使用
@RestController
进行注释,因此无需进行显式 json 转换。 Just return a POJO and jackson serializer will take care of converting to json.只需返回一个 POJO,jackson 序列化程序将负责转换为 json。 It is equivalent to using
@ResponseBody
when used with @Controller.与@Controller 一起使用时,相当于使用
@ResponseBody
。 Rather than placing @ResponseBody
on every controller method we place @RestController
instead of vanilla @Controller
and @ResponseBody
by default is applied on all resources in that controller.不是将
@ResponseBody
放置在每个控制器方法上,而是放置@RestController
而不是vanilla @Controller
,默认情况下@ResponseBody
应用于该控制器中的所有资源。
Refer this link: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-responsebody请参阅此链接: https : //docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-responsebody
The problem you are facing is because the returned object(JSONObject) does not have getter for certain properties.您面临的问题是因为返回的对象(JSONObject)没有某些属性的 getter。 And your intention is not to serialize this JSONObject but instead to serialize a POJO.
您的意图不是序列化这个 JSONObject,而是序列化一个 POJO。 So just return the POJO.
所以只需返回POJO。
Refer this link: https://stackoverflow.com/a/35822500/5039001请参阅此链接: https : //stackoverflow.com/a/35822500/5039001
If you want to return a json serialized string then just return the string.如果你想返回一个 json 序列化的字符串,那么只需返回该字符串。 Spring will use StringHttpMessageConverter instead of JSON converter in this case.
在这种情况下,Spring 将使用 StringHttpMessageConverter 而不是 JSON 转换器。
The reason why your current approach doesn't work is because Jackson is used by default to serialize and to deserialize objects.您当前的方法不起作用的原因是因为默认情况下使用 Jackson 来序列化和反序列化对象。 However, it doesn't know how to serialize the
JSONObject
.但是,它不知道如何序列化
JSONObject
。 If you want to create a dynamic JSON structure, you can use a Map
, for example:如果要创建动态 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;
}
This will lead to the following JSON response:这将导致以下 JSON 响应:
{ "key": "value", "foo": "bar", "aa": "bb" }
This is a bit limited, since it may become a bit more difficult to add child objects.这有点受限制,因为添加子对象可能会变得更加困难。 Jackson has its own mechanism though, using
ObjectNode
and ArrayNode
. Jackson 有自己的机制,使用
ObjectNode
和ArrayNode
。 To use it, you have to autowire ObjectMapper
in your service/controller.要使用它,您必须在服务/控制器中自动装配
ObjectMapper
。 Then you can use:然后你可以使用:
@GetMapping
public ObjectNode sayHello() {
ObjectNode objectNode = mapper.createObjectNode();
objectNode.put("key", "value");
objectNode.put("foo", "bar");
objectNode.put("number", 42);
return objectNode;
}
This approach allows you to add child objects, arrays, and use all various types.这种方法允许您添加子对象、数组并使用所有各种类型。
You can either return a response as String
as suggested by @vagaasen or you can use ResponseEntity
Object provided by Spring as below.您可以按照@vagaasen 的建议将响应作为
String
返回,也可以使用 Spring 提供的ResponseEntity
对象,如下所示。 By this way you can also return Http status code
which is more helpful in webservice call.通过这种方式,您还可以返回
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);
}
}
you can also use a hashmap for this您也可以为此使用哈希图
@GetMapping
public HashMap<String, Object> get() {
HashMap<String, Object> map = new HashMap<>();
map.put("key1", "value1");
map.put("results", somePOJO);
return map;
}
More correct create DTO for API queries, for example entityDTO:更正确的为 API 查询创建 DTO,例如 entityDTO:
@GetMapping(produces=MediaType.APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) public List<EntityDto> getAll() { return entityService.getAllEntities(); }
But if you need return different Map parameters you can use next two examples但是如果你需要返回不同的 Map 参数,你可以使用接下来的两个例子
2. For return one parameter like map: 2. 返回一个参数,如 map:
@GetMapping(produces=MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<Object> getOneParameterMap() { return ResponseEntity.status(HttpStatus.CREATED).body( Collections.singletonMap("key", "value")); }
@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")); }
@RequestMapping("/api/status")
public Map doSomething()
{
return Collections.singletonMap("status", myService.doSomething());
}
PS.附注。 Works only for 1 value
仅适用于 1 个值
use ResponseEntity<ResponseBean>
使用
ResponseEntity<ResponseBean>
Here you can use ResponseBean or Any java bean as you like to return your api response and it is the best practice.在这里,您可以根据需要使用 ResponseBean 或 Any java bean 来返回 api 响应,这是最佳实践。 I have used Enum for response.
我使用 Enum 进行响应。 it will return status code and status message of API.
它将返回 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);
}
for response ServiceStatus or(ResponseBody)用于响应 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;
}
}
Spring REST API should have below key in response Spring REST API 应该具有以下键作为响应
you will get final response below您将在下面得到最终答复
{
"StatusCode" : "0",
"Message":"Login success"
}
you can use ResponseBody(java POJO, ENUM,etc..) as per your requirement.您可以根据您的要求使用 ResponseBody(java POJO、ENUM 等)。
If you need to return a JSON object using a String, then the following should work:如果您需要使用字符串返回 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);
}
...
}
I use to return Map<String,Object> in the Controller by using the toMap() method of org.json.JSONObject as follows.我使用 org.json.JSONObject 的 toMap() 方法在控制器中返回 Map<String,Object> ,如下所示。
@GetMapping("/json")
public Map<String, Object> getJsonOutput() {
JSONObject jsonObject = new JSONObject();
//construct jsonObject here
return jsonObject.toMap();
}
you can do this :你可以这样做 :
@RestController
@RequestMapping("/api")
class MyRestController
{
@GetMapping(path = "/hello")
public JSONObject sayHello()
{
return new JSONObject("{'aa':'bb'}").toMap();;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.