Spring Boot响应body未转为JSON格式问题求助
Spring Boot中ApiResponse的body字段无法转为JSON结构问题
问题描述
Spring Boot项目返回的ApiResponse实体中,多数字段已正常序列化为JSON格式,但body字段始终以字符串形式返回(如"{\"status\":\"Healthy!\"}"),无法自动解析为嵌套的JSON结构。
项目相关代码
pom.xml依赖配置
<dependencies> <!--OpenAPI Generator Dependencies--> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <version>2.0.2</version> </dependency> <!--Http Dependencies--> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> </dependency> <!--Log4j Dependencies--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> <!--Spring Framework Dependencies--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <!--Dotenv Dependencies--> <dependency> <groupId>io.github.cdimascio</groupId> <artifactId>java-dotenv</artifactId> <version>${dotenv.version}</version> </dependency> <!--JSON Object Dependencies--> <dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> <version>20220924</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.14.1</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.14.1</version> </dependency> </dependencies>
ApiResponse实体类
public class ApiResponse { // class used to model api response data public Integer statusCode; public String statusReason; public String statusLine; public String url; public String body; public ProtocolVersion protocolVersion; public String getStatusLine() { return statusLine; } public void setStatusLine(String statusLine) { this.statusLine = statusLine; } public ProtocolVersion getProtocolVersion() { return protocolVersion; } public String getStatusReason() { return statusReason; } public void setStatusReason(String statusReason) { this.statusReason = statusReason; } public void setProtocolVersion(ProtocolVersion protocolVersion) { this.protocolVersion = protocolVersion; } public Integer getStatusCode() { return statusCode; } public void setStatusCode(Integer statusCode) { this.statusCode = statusCode; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getBody() { return body; } public void setBody(String body) { this.body = body; } }
processResponse方法
public ApiResponse processResponse(CloseableHttpResponse response) throws IOException { // process custom apache httpClient response ApiResponse apiResponse = new ApiResponse(); apiResponse.setProtocolVersion(response.getProtocolVersion()); apiResponse.setStatusCode(response.getStatusLine().getStatusCode()); apiResponse.setStatusReason(response.getStatusLine().getReasonPhrase()); apiResponse.setStatusLine(response.getStatusLine().toString()); HttpEntity entity = response.getEntity(); if (entity != null) { // return it as a String String result = EntityUtils.toString(entity); apiResponse.setBody(result); } response.close(); return apiResponse; }
getCall接口方法
@GetMapping(value = "/getHealth", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<ApiResponse> getClientHealth() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException { Client clientSetup = new Client(dotEnv.get("URL"), 80); try { ApiResponse response = clientSetup.getHealth(); return new ResponseEntity<>(response, HttpStatusCode.valueOf(response.getStatusCode())); } catch (Exception e) { throw new RuntimeException(e); } }
当前返回响应示例
{ "statusCode": 200, "statusReason": "OK", "statusLine": "HTTP/1.1 200 OK", "url": null, "body": "{\"status\":\"Healthy!\"}", "protocolVersion": { "protocol": "HTTP", "major": 1, "minor": 1 } }
解决方案
方案1:动态解析为Object类型(通用场景)
- 修改
ApiResponse实体类的body字段类型为Object:
public Object body; // 对应getter/setter修改 public Object getBody() { return body; } public void setBody(Object body) { this.body = body; }
- 在
processResponse方法中,使用Jackson的ObjectMapper将JSON字符串反序列化为Object:
import com.fasterxml.jackson.databind.ObjectMapper; public ApiResponse processResponse(CloseableHttpResponse response) throws IOException { // 原有代码保持不变 HttpEntity entity = response.getEntity(); if (entity != null) { String result = EntityUtils.toString(entity); // 新增反序列化逻辑 ObjectMapper mapper = new ObjectMapper(); apiResponse.setBody(mapper.readValue(result, Object.class)); } response.close(); return apiResponse; }
方案2:使用固定实体类(结构明确场景)
如果body的JSON结构固定(如示例中的{"status":"Healthy!"}),可以创建对应实体类来提升类型安全性:
- 创建
HealthResponse实体类:
public class HealthResponse { private String status; // getter和setter public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } }
- 修改
ApiResponse的body字段类型为HealthResponse:
public HealthResponse body; // 对应getter/setter修改 public HealthResponse getBody() { return body; } public void setBody(HealthResponse body) { this.body = body; }
- 在
processResponse方法中反序列化为指定类型:
apiResponse.setBody(mapper.readValue(result, HealthResponse.class));
方案3:自定义Jackson序列化器(复杂场景)
如果无法修改ApiResponse的字段类型,可以自定义序列化器对String类型的body进行解析:
- 创建自定义序列化器:
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; public class JsonStringSerializer extends JsonSerializer<String> { private final ObjectMapper mapper = new ObjectMapper(); @Override public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException { if (value != null && value.startsWith("{") && value.endsWith("}")) { // 将JSON字符串写入为JSON结构 mapper.readTree(value).serialize(gen, serializers); } else { // 非JSON字符串按原格式输出 gen.writeString(value); } } }
- 在
ApiResponse的body字段上添加注解:
import com.fasterxml.jackson.databind.annotation.JsonSerialize; @JsonSerialize(using = JsonStringSerializer.class) public String body;
以上三种方案均可解决body字段以字符串形式返回的问题,根据实际业务场景选择即可。
内容的提问来源于stack exchange,提问作者Ryan Burch
相关产品推荐
相关产品推荐

