You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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类型(通用场景)

  1. 修改ApiResponse实体类的body字段类型为Object:
public Object body;

// 对应getter/setter修改
public Object getBody() {
    return body;
}

public void setBody(Object body) {
    this.body = body;
}
  1. 在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!"}),可以创建对应实体类来提升类型安全性:

  1. 创建HealthResponse实体类:
public class HealthResponse {
    private String status;

    // getter和setter
    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }
}
  1. 修改ApiResponse的body字段类型为HealthResponse:
public HealthResponse body;

// 对应getter/setter修改
public HealthResponse getBody() {
    return body;
}

public void setBody(HealthResponse body) {
    this.body = body;
}
  1. 在processResponse方法中反序列化为指定类型:
apiResponse.setBody(mapper.readValue(result, HealthResponse.class));

方案3:自定义Jackson序列化器(复杂场景)

如果无法修改ApiResponse的字段类型,可以自定义序列化器对String类型的body进行解析:

  1. 创建自定义序列化器:
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);
        }
    }
}
  1. 在ApiResponse的body字段上添加注解:
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

@JsonSerialize(using = JsonStringSerializer.class)
public String body;

以上三种方案均可解决body字段以字符串形式返回的问题,根据实际业务场景选择即可。

内容的提问来源于stack exchange,提问作者Ryan Burch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 14:35:26