Spring実戦第5版Spring HATEOAS部分コードをSpring HATEOAS 1.0に移行
19977 ワード
最近Spring実戦第5版の中国語版を読んでいます.本の第6章ではSpring HATEOASの一部のコードについてSpring HATEOAS 0.25のバージョンを使用していますが、最新のSpring HATEOAS 1.0は旧版のAPIをアップグレードしています.新版Spring Boot(記事公開日現在の最新Spring Bootバージョン2.2.4)でロードされているSpring HATEOAS 1.0.3では、本書のコードが正常に動作しないため、本書のコードを移行・アップグレードすることにしました.
本のこの部分をオンラインで読む:https://potoyang.gitbook.io/spring-in-action-v5/di-6-zhang-chuang-jian-rest-fu-wu/6.2-qi-yong-chao-mei-ti
Spring HATEOAS 1.0バージョンの変更
パッケージ構造の最大の変化は、Spring HATEOASにおける他のメディアタイプをサポートするために、スーパーメディアタイプ登録APIを導入することによって達成される.これにより、クライアントAPIとサーバAPI(それぞれ命名されたパケット)と、パケット内のメディアタイプとの明確な分離
最大の変化は,元のリソースをモデルとして表すことであり,具体的な変化は以下の通りである. である. である. である. である.
したがって、 この は、
また、ResourceProcessorインタフェースはRepresentationModelProcessorに置き換えられていることに注意してください.
詳細については、Spring HATEOASドキュメントを参照してください.https://spring.io/projects/spring-hateoas
コード移行のアップグレード
本書中のプログラムリスト6.4リソースにハイパーリンクを追加
削除URLハードコーディング
プログラムリスト6.5レルムデータとハイパーリンクリストtacoリソースを携帯可能
プログラムリスト6.6 tacoリソースをアセンブリするリソースアセンブリ
その後recentTacos()の調整
IngredientResourceオブジェクトの作成
IngredientResourceAssemblerオブジェクト
TacoResourceオブジェクトの変更
プログラムリスト6.7
プログラムリスト6.8 Spring Data RESTエンドポイントにカスタムリンクを追加
もう一つの書き方
リソースアセンブリを書くのが面倒だと思ったら、この方法を採用することもできます.
参照元:https://github.com/spring-projects/spring-hateoas-examples/tree/master/simplified
END
本のこの部分をオンラインで読む:https://potoyang.gitbook.io/spring-in-action-v5/di-6-zhang-chuang-jian-rest-fu-wu/6.2-qi-yong-chao-mei-ti
Spring HATEOAS 1.0バージョンの変更
パッケージ構造の最大の変化は、Spring HATEOASにおける他のメディアタイプをサポートするために、スーパーメディアタイプ登録APIを導入することによって達成される.これにより、クライアントAPIとサーバAPI(それぞれ命名されたパケット)と、パケット内のメディアタイプとの明確な分離
mediatype
がもたらされる.最大の変化は,元のリソースをモデルとして表すことであり,具体的な変化は以下の通りである.
ResourceSupport
/Resource
/Resources
/PagedResources
/ResourceSupport
のクラスでは、適切な命名が実際に感じられなかった.結局、これらのタイプは実際にはリソースではなく、モデルを表し、スーパーメディア情報と提供されたコンテンツを通じてそれらを豊かにすることができます.これは、新しい名前を古い名前にマッピングする方法です.RepresentationModel
は現在のResource
EntityModel
は現在のResources
CollectionModel
は現在のPagedResources
PagedModel
は現在のResourceAssembler
したがって、
RepresentationModelAssembler
は、toResource(…)
およびその方法toResources(…)
として名前が変更され、それぞれtoModel(…)
は、toCollectionModel(…)
およびTypeReferences
として名前が変更された.名前の変更は、に含まれるクラスRepresentationModel.getLinks()
にも反映されます.Links
は、様々なポリシーを使用して異なるインスタンスを接続およびマージする他のAPIを開示するList
のインスタンス(Links
を介して)を開示する.同様に、インスタンスにリンクを追加する方法でインスタンス自体を返すことができるように、自己バインドされた汎用タイプとなっている.LinkDiscoverer
APIは、client
パケットに移動した.LinkBuilder
およびEntityLinks
APIでserver
パケットに移動された.ControllerLinkBuilder
はserver.mvc
に移入されており、代替WebMvcLinkBuilder
の使用は推奨されていない.RelProvider
は、LinkRelationProvider
と名前を変更し、LinkRelation
ではなくString
のインスタンスを返します.VndError
がmediatype.vnderror
キットに移動しました.また、ResourceProcessorインタフェースはRepresentationModelProcessorに置き換えられていることに注意してください.
詳細については、Spring HATEOASドキュメントを参照してください.https://spring.io/projects/spring-hateoas
コード移行のアップグレード
本書中のプログラムリスト6.4リソースにハイパーリンクを追加
@GetMapping("/recent")
public CollectionModel> recentTacos() {
PageRequest page = PageRequest.of(
0, 12, Sort.by("createdAt").descending());
List tacos = tacoRepo.findAll(page).getContent();
CollectionModel> recentResources = CollectionModel.wrap(tacos);
recentResources.add(
new Link("http://localhost:8080/design/recent", "recents"));
return recentResources;
}
削除URLハードコーディング
@GetMapping("/recent")
public CollectionModel> recentTacos() {
PageRequest page = PageRequest.of(
0, 12, Sort.by("createdAt").descending());
List tacos = tacoRepo.findAll(page).getContent();
CollectionModel> recentResources = CollectionModel.wrap(tacos);
recentResources.add(
linkTo(methodOn(DesignTacoController.class).recentTacos()).withRel("recents"));
return recentResources;
}
プログラムリスト6.5レルムデータとハイパーリンクリストtacoリソースを携帯可能
public class TacoResource extends RepresentationModel {
@Getter
private String name;
@Getter
private Date createdAt;
@Getter
private List ingredients;
public TacoResource(Taco taco) {
this.name = taco.getName();
this.createdAt = taco.getCreatedAt();
this.ingredients = taco.getIngredients();
}
}
プログラムリスト6.6 tacoリソースをアセンブリするリソースアセンブリ
public class TacoResourceAssembler extends RepresentationModelAssemblerSupport {
/**
* Creates a new {@link RepresentationModelAssemblerSupport} using the given controller class and resource type.
*
* @param controllerClass DesignTacoController {@literal DesignTacoController}.
* @param resourceType TacoResource {@literal TacoResource}.
*/
public TacoResourceAssembler(Class> controllerClass, Class resourceType) {
super(controllerClass, resourceType);
}
@Override
protected TacoResource instantiateModel(Taco taco) {
return new TacoResource(taco);
}
@Override
public TacoResource toModel(Taco entity) {
return createModelWithId(entity.getId(), entity);
}
}
その後recentTacos()の調整
@GetMapping("/recentNew")
public CollectionModel recentTacos() {
PageRequest page = PageRequest.of(
0, 12, Sort.by("createdAt").descending());
List tacos = tacoRepo.findAll(page).getContent();
CollectionModel tacoResources =
new TacoResourceAssembler(DesignTacoController.class, TacoResource.class).toCollectionModel(tacos);
tacoResources.add(linkTo(methodOn(DesignTacoController.class)
.recentTacos())
.withRel("recents"));
return tacoResources;
}
IngredientResourceオブジェクトの作成
@Data
public class IngredientResource extends RepresentationModel {
public IngredientResource(Ingredient ingredient) {
this.name = ingredient.getName();
this.type = ingredient.getType();
}
private final String name;
private final Ingredient.Type type;
}
IngredientResourceAssemblerオブジェクト
public class IngredientResourceAssembler extends RepresentationModelAssemblerSupport {
/**
* Creates a new {@link RepresentationModelAssemblerSupport} using the given controller class and resource type.
*
* @param controllerClass IngredientController {@literal IngredientController}.
* @param resourceType IngredientResource {@literal IngredientResource}.
*/
public IngredientResourceAssembler(Class> controllerClass, Class resourceType) {
super(controllerClass, resourceType);
}
@Override
protected IngredientResource instantiateModel(Ingredient entity) {
return new IngredientResource(entity);
}
@Override
public IngredientResource toModel(Ingredient entity) {
return createModelWithId(entity.getId(), entity);
}
}
TacoResourceオブジェクトの変更
public class TacoResource extends RepresentationModel {
private static final IngredientResourceAssembler
ingredientAssembler = new IngredientResourceAssembler(IngredientController.class, IngredientResource.class);
@Getter
private String name;
@Getter
private Date createdAt;
@Getter
private CollectionModel ingredients;
public TacoResource(Taco taco) {
this.name = taco.getName();
this.createdAt = taco.getCreatedAt();
this.ingredients = ingredientAssembler.toCollectionModel(taco.getIngredients());
}
}
プログラムリスト6.7
@RepositoryRestController
public class RecentTacosController {
private TacoRepository tacoRepo;
public RecentTacosController(TacoRepository tacoRepo) {
this.tacoRepo = tacoRepo;
}
/**
* @GetMapping “/tacos/recent” , @Repository RestController
* Spring Data REST 。 ,recentTacos() “/api/tacos/recent” GET 。
* */
@GetMapping(path="/tacos/recent", produces="application/hal+json")
public ResponseEntity> recentTacos() {
PageRequest page = PageRequest.of(
0, 12, Sort.by("createdAt").descending());
List tacos = tacoRepo.findAll(page).getContent();
CollectionModel tacoResources =
new TacoResourceAssembler(DesignTacoController.class, TacoResource.class).toCollectionModel(tacos);
tacoResources.add(
linkTo(methodOn(RecentTacosController.class).recentTacos())
.withRel("recents"));
return new ResponseEntity<>(tacoResources, HttpStatus.OK);
}
}
プログラムリスト6.8 Spring Data RESTエンドポイントにカスタムリンクを追加
@Bean
public RepresentationModelProcessor>> tacoProcessor(EntityLinks links) {
return new RepresentationModelProcessor>>() {
@Override
public PagedModel> process(PagedModel> resource) {
resource.add(
links.linkFor(Taco.class)
.slash("recent")
.withRel("recents"));
return resource;
}
};
}
もう一つの書き方
リソースアセンブリを書くのが面倒だと思ったら、この方法を採用することもできます.
@GetMapping("/employees")
public ResponseEntity>> findAll() {
PageRequest page = PageRequest.of(
0, 12, Sort.by("createdAt").descending());
List> employees = StreamSupport.stream(tacoRepo.findAll(page).spliterator(), false)
.map(employee -> new EntityModel<>(employee,
linkTo(methodOn(DesignTacoController.class).findOne(employee.getId())).withSelfRel(),
linkTo(methodOn(DesignTacoController.class).findAll()).withRel("employees")))
.collect(Collectors.toList());
return ResponseEntity.ok(
new CollectionModel<>(employees,
linkTo(methodOn(DesignTacoController.class).findAll()).withSelfRel()));
}
@GetMapping("/employees/{id}")
public ResponseEntity> findOne(@PathVariable long id) {
return tacoRepo.findById(id)
.map(employee -> new EntityModel<>(employee,
linkTo(methodOn(DesignTacoController.class).findOne(employee.getId())).withSelfRel(), //
linkTo(methodOn(DesignTacoController.class).findAll()).withRel("employees"))) //
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
参照元:https://github.com/spring-projects/spring-hateoas-examples/tree/master/simplified
END