44

Spring 4.0.0.RELEASE、Spring Data Commons 1.7.0.M1、Spring Hateoas 0.8.0.RELEASE を使用しています。

私のリソースは単純な POJO です。

public class UserResource extends ResourceSupport { ... }

リソース アセンブラーは、User オブジェクトを UserResource オブジェクトに変換します。

@Component
public class UserResourceAssembler extends ResourceAssemblerSupport<User, UserResource> { 
    public UserResourceAssembler() {
        super(UserController.class, UserResource.class);
    }

    @Override
    public UserResource toResource(User entity) {
        // map User to UserResource
    }
}

UserController 内で、サービスから取得し、次に示すようにusingにPage<User>変換します: https://stackoverflow.com/a/16794740/1321564PagedResources<UserResource>PagedResourcesAssembler

@RequestMapping(value="", method=RequestMethod.GET)
PagedResources<UserResource> get(@PageableDefault Pageable p, PagedResourcesAssembler assembler) {
    Page<User> u = service.get(p)
    return assembler.toResource(u);
}

これは呼び出さUserResourceAssemblerれず、単にUsercustom の代わりに の内容が返されますUserResource

単一のリソースを返すと動作します:

@Autowired
UserResourceAssembler assembler;

@RequestMapping(value="{id}", method=RequestMethod.GET)
UserResource getById(@PathVariable ObjectId id) throws NotFoundException {
    return assembler.toResource(service.getById(id));
}

PagedResourcesAssembler一般的な引数を必要としますがT toResource(T)、 を に変換したくないため、特に は POJO でリソースがないため、 をPage<User>使用PagedResources<User>できUserません。

質問は次のとおりです。それはどのように機能しますか?

編集:

私の WebMvcConfigurationSupport:

@Configuration
@ComponentScan
@EnableHypermediaSupport
public class WebMvcConfig extends WebMvcConfigurationSupport {
    @Override
    protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(pageableResolver());
        argumentResolvers.add(sortResolver());
        argumentResolvers.add(pagedResourcesAssemblerArgumentResolver());
    }

    @Bean
    public HateoasPageableHandlerMethodArgumentResolver pageableResolver() {
        return new HateoasPageableHandlerMethodArgumentResolver(sortResolver());
    }

    @Bean
    public HateoasSortHandlerMethodArgumentResolver sortResolver() {
        return new HateoasSortHandlerMethodArgumentResolver();
    }

    @Bean
    public PagedResourcesAssembler<?> pagedResourcesAssembler() {
        return new PagedResourcesAssembler<Object>(pageableResolver(), null);
    }

    @Bean
    public PagedResourcesAssemblerArgumentResolver pagedResourcesAssemblerArgumentResolver() {
        return new PagedResourcesAssemblerArgumentResolver(pageableResolver(), null);
    }

    /* ... */
}

解決:

@Autowired
UserResourceAssembler assembler;

@RequestMapping(value="", method=RequestMethod.GET)
PagedResources<UserResource> get(@PageableDefault Pageable p, PagedResourcesAssembler pagedAssembler) {
    Page<User> u = service.get(p)
    return pagedAssembler.toResource(u, assembler);
}
4

3 に答える 3

79

あなたはすでに適切な使用方法を知っているようですが、他の人にも見つけてもらうために、ここでいくつかの詳細を説明したいと思います. この回答PagedResourceAssemblerで同様の詳細を説明しました。

表現モデル

Spring HATEOAS には、リンクを備えた表現を簡単に作成できる表現モデルのさまざまな基本クラスが付属しています。標準で提供されている 3 種類のクラスがあります。

  • Resource- アイテム リソース。単一のアイテムをキャプチャしてリンクで強化する DTO またはエンティティを効果的にラップします。
  • Resources- 何かのコレクションである可能性がありますが、通常はResourceインスタンスのコレクションであるコレクション リソース。
  • PagedResourcesResources-総ページ数などの追加のページネーション情報を取得する拡張機能。

これらのクラスはすべて、インスタンスResourceSupportの基本コンテナであるから派生しLinkます。

リソース アセンブラ

AResourceAssemblerは、ドメイン オブジェクトまたは DTO をそのようなリソース インスタンスに変換する軽減コンポーネントになりました。ここで重要なのは、1 つのソース オブジェクトを1 つのターゲット オブジェクトに変換することです。

したがって、PagedResourcesAssemblerは Spring Data インスタンスを取得し、ページをナビゲートするために必要なおよびリンクを評価して作成することによりPage、それをインスタンスに変換します。デフォルトでは、これがおそらくここで興味深い部分です。プレーン( の内部クラス) を使用して、ページの個々の要素をネストされたインスタンスに変換します。PagedResourcesPagePageMetadataprevnextSimplePagedResourceAssemblerPRAResource

これをカスタマイズできるようにするために、デリゲートを使用して個々のアイテムを処理するPRA追加のメソッドがあります。したがって、次のような結果になります。toResource(…)ResourceAssembler

 class UserResource extends ResourceSupport { … }

 class UserResourceAssembler extends ResourceAssemblerSupport<User, UserResource> { … }

クライアントコードは次のようになります。

 PagedResourcesAssembler<User> parAssembler = … // obtain via DI
 UserResourceAssembler userResourceAssembler = … // obtain via DI

 Page<User> users = userRepository.findAll(new PageRequest(0, 10));

 // Tell PAR to use the user assembler for individual items.
 PagedResources<UserResource> pagedUserResource = parAssembler.toResource(
   users, userResourceAssembler);

見通し

今後の Spring Data Commons 1.7 RC1 (および推移的に Spring HATEOAS 0.9) の時点で、prevおよびnextリンクはRFC6540HandlerMethodArgumentResolvers準拠の URI テンプレートとして生成され、 forPageableおよびで構成されたページネーション要求パラメーターを公開しますSort

上記の構成は、構成クラスに注釈を付けることで簡素化できます。これにより、@EnableSpringDataWebSupportすべての明示的な Bean 宣言を取り除くことができます。

于 2014-01-26T10:29:11.727 に答える
-7

別の方法

もう 1 つの方法は、Range HTTP ヘッダーを使用することです (詳細についてはRFC 7233を参照してください)。次の方法で HTTP ヘッダーを定義できます。

Range: resources=20-41

つまり、20 から 41 (含む) のリソースを取得する必要があります。この方法により、API の消費者は正確に定義されたリソースを受け取ることができます。

それは単なる代替方法です。範囲は、別の単位 (バイトなど) と一緒に使用されることがよくあります。

推奨される方法

ページネーションを使用し、実際に適用可能な API (ハイパーメディア / HATEOAS を含む) を使用する場合は、URL に Page と PageSize を追加することをお勧めします。例:

http://host.loc/articles?Page=1&PageSize=20

次に、このデータを BaseApiController で読み取り、すべてのリクエストで QueryFilter オブジェクトを作成できます。

{
    var requestHelper = new RequestHelper(Request);

    int page = requestHelper.GetValueFromQueryString<int>("page");
    int pageSize = requestHelper.GetValueFromQueryString<int>("pagesize");

    var filter = new QueryFilter
    {
        Page = page != 0 ? page : DefaultPageNumber,
        PageSize = pageSize != 0 ? pageSize : DefaultPageSize
    };

    return filter;
}

API は、アイテム数に関する情報を含む特別なコレクションを返す必要があります。

public class ApiCollection<T>
{
    public ApiCollection()
    {
        Data = new List<T>();
    }

    public ApiCollection(int? totalItems, int? totalPages)
    {
        Data = new List<T>();
        TotalItems = totalItems;
        TotalPages = totalPages;
    }

    public IEnumerable<T> Data { get; set; }

    public int? TotalItems { get; set; }
    public int? TotalPages { get; set; }
}

モデル クラスは、ページネーションをサポートするいくつかのクラスを継承できます。

public abstract class ApiEntity
{
    public List<ApiLink> Links { get; set; }
}

public class ApiLink
{
    public ApiLink(string rel, string href)
    {
        Rel = rel;
        Href = href;
    }

    public string Href { get; set; }

    public string Rel { get; set; }
}
于 2014-10-21T08:46:04.727 に答える