返回含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,提问作者Шатов Данил
相关产品推荐
相关产品推荐

