缩减Spring Data Repository返回JSON大小及微服务数据加载优化
嘿,针对你遇到的两个问题——通用的Spring Data Repository返回JSON体积过大,以及微服务启动时加载运营商数据遇到的HAL链接字段冗余问题,我整理了几个实用的解决方案,应该能帮你搞定:
一、通用Spring Data Repository JSON体积优化方案
这些方法适用于大多数需要减小JSON响应体积的场景:
- 用DTO替代实体类返回:别直接返回JPA实体,创建只包含业务需要字段的DTO(数据传输对象),通过构造函数映射或者MapStruct、ModelMapper这类工具完成转换。比如你的运营商数据,只保留
enabled、code、operatorName这些必要字段,完全规避实体里的冗余属性和框架自动生成的链接。 - Jackson序列化精细化配置:
- 忽略空值:在
application.yml里添加配置:
或者在实体/DTO类上标注spring: jackson: default-property-inclusion: non_null@JsonInclude(JsonInclude.Include.NON_NULL),自动剔除空字段。 - 禁用不必要的序列化特性:比如关闭Jackson的
FAIL_ON_UNKNOWN_PROPERTIES,减少序列化时的额外开销。
- 忽略空值:在
- 开启响应压缩:在服务端启用Gzip压缩,Spring Boot只需简单配置:
传输时JSON体积会大幅压缩,客户端也能自动解压,对批量数据传输效果特别明显。server: compression: enabled: true mime-types: application/json - 按需加载/分页:如果不是必须一次性加载全量数据,用
Page<Entity>分页返回,但你的场景是启动时全量加载,这个方法可能不适用,但还是提一下通用场景。
二、针对Feign/Data-Rest加载全量运营商数据的专项优化
你的场景里响应占比近一半的链接字段,是因为Spring Data Rest默认返回HAL格式的JSON,包含了资源的导航链接,但对于启动时全量加载数据的场景,这些链接完全是冗余的,重点解决这个问题:
方案1:自定义Repository接口,返回纯DTO列表
不要用Spring Data Rest自动生成的端点,自己写Repository方法返回DTO列表,彻底绕过HAL格式:
// 自定义Repository public interface OperatorCodeRepository extends JpaRepository<OperatorCode, Long> { // 直接返回DTO列表,可通过构造函数查询或投影实现 List<OperatorCodeDto> findAll(); } // 对应的DTO类,只保留业务需要的字段 public class OperatorCodeDto { private Boolean enabled; private Integer code; private Long operatorCodeId; private String operatorName; private Long operatorId; private String activationDate; // 构造函数、getter方法 }
然后在Feign客户端调用这个自定义接口,返回的就是纯JSON数组,没有_embedded和_links这类冗余结构。
方案2:全局关闭Spring Data Rest的HAL格式
如果你的服务不需要HAL风格的REST API,可以全局禁用:
@Configuration public class DataRestConfig implements RepositoryRestConfigurer { @Override public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { config.setDefaultMediaType(MediaType.APPLICATION_JSON); config.useHalAsDefaultJsonMediaType(false); } }
这样Spring Data Rest返回的JSON就会是纯实体数组,不再包含HAL特有的链接字段,体积能直接减少近一半。
方案3:使用Spring Data投影(Projection)
定义一个投影接口,只暴露需要的字段,让Repository返回投影实例:
// 投影接口,指定要保留的字段 @Projection(name = "compact", types = OperatorCode.class) public interface OperatorCodeCompactProjection { Boolean getEnabled(); Integer getCode(); Long getOperatorCodeId(); String getOperatorName(); Long getOperatorId(); String getActivationDate(); } // 在Repository中使用投影 public interface OperatorCodeRepository extends JpaRepository<OperatorCode, Long> { List<OperatorCodeCompactProjection> findAll(); }
配合关闭HAL格式,返回的JSON只会包含你需要的字段,完全没有冗余内容。
方案4:Feign客户端侧过滤冗余字段
如果无法修改提供数据的服务,可以在Feign客户端这边用Jackson忽略不需要的字段:
@FeignClient(name = "operator-service") public interface OperatorCodeFeignClient { @GetMapping("/operatorcodes") ResponseEntity<OperatorCodeWrapper> getAllOperatorCodes(); } // 包装类,只解析_embedded里的有效数据 public class OperatorCodeWrapper { @JsonProperty("_embedded") private EmbeddedData embedded; public static class EmbeddedData { @JsonProperty("operatorcode") private List<OperatorCodeDto> operatorCodes; // getter方法 } // getter方法 } // DTO类,忽略所有未知字段 @JsonIgnoreProperties(ignoreUnknown = true) public class OperatorCodeDto { private Boolean enabled; private Integer code; // 其他需要的字段和getter }
这样Feign客户端只会解析你需要的字段,多余的链接字段会被自动忽略,减少内存占用和传输体积。
内容的提问来源于stack exchange,提问作者Shahbour
相关产品推荐
相关产品推荐

