Spring HATEOAS:如何重命名第三方类的集合与项名称
嗨,这个场景我帮不少开发者处理过,既然没法修改第三方类加@Relation注解,咱们完全可以通过Spring HATEOAS自身的扩展能力来解决,下面几个方案都比硬套Jackson Mixins更贴合框架设计:
1. 自定义RelProvider(最推荐)
Spring HATEOAS的RelProvider是生成资源关系名称的核心组件,默认逻辑是基于类名转换或读取@Relation注解。我们可以实现自己的RelProvider,针对第三方类返回自定义的集合/项名称,其他类沿用默认逻辑:
@Component public class ThirdPartyRelProvider implements RelProvider { private static final String CUSTOM_ITEM_REL = "my-custom-item"; private static final String CUSTOM_COLLECTION_REL = "my-custom-items"; // 委托默认实现处理其他类 private final RelProvider delegate = DefaultRelProvider.INSTANCE; @Override public String getItemResourceRelFor(Class<?> type) { if (ThirdPartyObject.class.isAssignableFrom(type)) { return CUSTOM_ITEM_REL; } return delegate.getItemResourceRelFor(type); } @Override public String getCollectionResourceRelFor(Class<?> type) { if (ThirdPartyObject.class.isAssignableFrom(type)) { return CUSTOM_COLLECTION_REL; } return delegate.getCollectionResourceRelFor(type); } @Override public boolean supports(Class<?> type) { return ThirdPartyObject.class.isAssignableFrom(type) || delegate.supports(type); } }
注册这个组件后,Spring HATEOAS会自动用它生成第三方对象的资源关系名称,完全不需要修改原类。
2. 通过RepresentationModelAssembler手动控制资源关系
创建一个资源组装器,把第三方对象转换成EntityModel或CollectionModel,并手动指定关系名称:
@Component public class ThirdPartyAssembler implements RepresentationModelAssembler<ThirdPartyObject, EntityModel<ThirdPartyObject>> { @Override public EntityModel<ThirdPartyObject> toModel(ThirdPartyObject entity) { return EntityModel.of(entity, // 给单个资源指定自定义项rel linkTo(methodOn(ThirdPartyController.class).getById(entity.getId())).withRel("my-custom-item"), linkTo(methodOn(ThirdPartyController.class).getAll()).withRel("my-custom-items")); } // 处理集合资源,自定义集合rel @Override public CollectionModel<EntityModel<ThirdPartyObject>> toCollectionModel(Iterable<? extends ThirdPartyObject> entities) { CollectionModel<EntityModel<ThirdPartyObject>> collectionModel = super.toCollectionModel(entities); // 替换集合的默认rel为自定义名称 return collectionModel.withRel("my-custom-items") .add(linkTo(methodOn(ThirdPartyController.class).getAll()).withSelfRel()); } }
然后在Controller里直接用这个组装器转换返回:
@GetMapping("/third-party") public CollectionModel<EntityModel<ThirdPartyObject>> getAll() { List<ThirdPartyObject> objects = thirdPartyService.fetchAll(); return thirdPartyAssembler.toCollectionModel(objects); }
这种方式灵活性最高,还能顺便添加其他自定义链接。
3. 用Jackson Mixin配合@Relation(其实可行)
你之前觉得Mixin不合适,但其实Spring HATEOAS支持通过Mixin给第三方类注入@Relation注解,完全不需要修改原类:
首先定义Mixin类:
@JsonMixin(ThirdPartyObject.class) @Relation(collectionRelation = "my-custom-items", itemRelation = "my-custom-item") public abstract class ThirdPartyObjectMixin { // 不需要实现任何方法,仅作为注解载体 }
然后在Jackson配置中注册这个Mixin:
@Configuration public class JacksonConfig { @Bean public Module thirdPartyMixinModule() { SimpleModule module = new SimpleModule(); module.setMixInAnnotation(ThirdPartyObject.class, ThirdPartyObjectMixin.class); return module; } }
Spring HATEOAS会识别Mixin上的@Relation注解,效果和直接在原类上添加注解完全一样,这个方案适合不想写太多组装逻辑的场景。
总结一下:优先推荐自定义RelProvider(全局统一配置)或RepresentationModelAssembler(灵活控制单个资源),如果想快速复用@Relation的逻辑,Mixin方案也是完全可行的。
内容的提问来源于stack exchange,提问作者Kerruba

