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(それぞれ命名されたパケット)と、パケット内のメディアタイプとの明確な分離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パケットに移動された.
  • ControllerLinkBuilderserver.mvcに移入されており、代替WebMvcLinkBuilderの使用は推奨されていない.
  • RelProviderは、LinkRelationProviderと名前を変更し、LinkRelationではなくStringのインスタンスを返します.
  • VndErrormediatype.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