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

返回含Resource与普通对象的响应时遇HttpMessageConversionException如何解决?

解决返回包含Resource和普通对象的响应时的序列化错误

错误核心是Jackson无法序列化InputStreamResource中的BufferedInputStream字段——该类没有默认的序列化器,且Jackson找不到可用于生成BeanSerializer的属性。以下是几种可行的解决方案:

方案一:拆分接口(推荐)

将配置信息和文件资源分开返回,符合REST接口单一职责原则,彻底避免序列化冲突:

配置信息接口

@GetMapping(DEVICE_ID_PATH + "/config")
public ResponseEntity<ConfigResponse> getDeviceConfig(@PathVariable(name = "id") Long id) {
    log.debug("REST request to get config for device with id = {}", id);
    var deviceSummary = mobileComplexService.getSummary(id);
    return ResponseEntity.ok(deviceSummaryMapper.toConfigResponse(deviceSummary));
}

GPX文件接口

@GetMapping(DEVICE_ID_PATH + "/route")
public ResponseEntity<Resource> getDeviceRoute(@PathVariable(name = "id") Long id) {
    log.debug("REST request to get route GPX for device with id = {}", id);
    var deviceSummary = mobileComplexService.getSummary(id);
    Resource route = deviceSummary.getRoute();
    return ResponseEntity.ok()
            .header(HttpHeaders.CONTENT_TYPE, "application/gpx+xml")
            .header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"device-route.gpx\"")
            .body(route);
}

方案二:将Resource转为Base64字符串嵌入DTO

把GPX文件内容转为Base64编码的字符串,作为DTO字段返回:

修改响应DTO

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class DeviceSummaryResponse {
    @ApiModelProperty(value = "Конфигурация устройства", required = true)
    private ConfigResponse config;

    @ApiModelProperty(value = "GPX файл с маршрутом устройства(Base64编码)", required = true)
    private String routeBase64;
}

修改转换逻辑

public DeviceSummaryResponse toResponse(DeviceSummary deviceSummary) {
    ConfigResponse config = mapToConfigResponse(deviceSummary.getConfig());
    Resource route = deviceSummary.getRoute();
    String routeBase64;

    try (InputStream inputStream = route.getInputStream()) {
        byte[] fileBytes = org.apache.commons.io.IOUtils.toByteArray(inputStream);
        routeBase64 = Base64.getEncoder().encodeToString(fileBytes);
    } catch (IOException e) {
        throw new RuntimeException("读取GPX文件失败", e);
    }

    return DeviceSummaryResponse.builder()
            .config(config)
            .routeBase64(routeBase64)
            .build();
}

方案三:自定义Jackson序列化器处理Resource

编写自定义序列化器,控制Resource字段的序列化逻辑:

自定义序列化器

public class ResourceSerializer extends JsonSerializer<Resource> {
    @Override
    public void serialize(Resource resource, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (resource == null) {
            gen.writeNull();
            return;
        }

        gen.writeStartObject();
        gen.writeStringField("filename", resource.getFilename());
        gen.writeNumberField("size", resource.contentLength());
        gen.writeStringField("contentType", resource.getContentType());

        // 可选:添加Base64编码的文件内容
        try (InputStream is = resource.getInputStream()) {
            byte[] contentBytes = org.apache.commons.io.IOUtils.toByteArray(is);
            gen.writeStringField("contentBase64", Base64.getEncoder().encodeToString(contentBytes));
        }

        gen.writeEndObject();
    }
}

应用序列化器到DTO字段

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class DeviceSummaryResponse {
    @ApiModelProperty(value = "Конфигурация устройства", required = true)
    private ConfigResponse config;

    @ApiModelProperty(value = "GPX файл с маршрутом устройства", required = true)
    @JsonSerialize(using = ResourceSerializer.class)
    private Resource route;
}

内容的提问来源于stack exchange,提问作者Шатов Данил

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 13:30:31