Как правильно использовать PagedResourcesAssembler из данных Spring?
я использую Spring 4.0.0.Выпуск, Spring Data Commons 1.7.0.M1, Spring Hateoas 0.8.0.Отпустите
мой ресурс-это простой POJO:
public class UserResource extends ResourceSupport { ... }
мой ассемблер ресурсов преобразует пользовательские объекты в объекты 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 я хочу получить Page<User>
из моего сервиса, а затем преобразовать его в PagedResources<UserResource>
используя PagedResourcesAssembler
, как показано здесь: https://stackoverflow.com/a/16794740/1321564
@RequestMapping(value="", method=RequestMethod.GET)
PagedResources<UserResource> get(@PageableDefault Pageable p, PagedResourcesAssembler assembler) {
Page<User> u = service.get(p)
return assembler.toResource(u);
}
это не вызов UserResourceAssembler
и просто содержание User
возвращаются вместо моего custom 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)
, потому что я не хочу конвертировать мой Page<User>
to PagedResources<User>
, особенно User
является POJO и нет ресурсов.
так вопрос в том, как это работает?
EDIT:
Мой 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);
}
2 ответов
Вы, кажется, уже узнали о правильном пути, чтобы использовать, но я хотела бы вдаваться в некоторые детали здесь немного для других, чтобы найти. Я пошел в аналогичную деталь о PagedResourceAssembler
на ответ.
модели представления
Spring HATEOAS поставляется с различными базовыми классами для моделей представления, которые позволяют легко создавать представления, оснащенные ссылками. Существует три типа классов из box:
-
Resource
- элемент ресурсов. Эффективно обернуть вокруг некоторого DTO или сущности, которая захватывает один пункт и обогащает его ссылками. -
Resources
- ресурс коллекции, который может быть коллекцией чего-то, но обычно является коллекциейResource
экземпляров. -
PagedResources
- расширениеResources
это захватывает дополнительную информацию о разбиении на страницы, такую как количество общих страниц и т. д.
все из этих классов происходят от ResourceSupport
, который является основным контейнером для Link
экземпляров.
ресурс монтажники
A ResourceAssembler
теперь является смягчающим компонентом для преобразования объектов домена или DTOs в такие экземпляры ресурсов. Важная часть здесь в том, что получается один источник один целевого объекта.
так PagedResourcesAssembler
возьму весенние данные Page
экземпляр и преобразовать его в PagedResources
экземпляр путем оценки Page
и создание необходимых PageMetadata
а также prev
и next
ссылки для навигации по страницам. По умолчанию - и это, вероятно, интересная часть здесь - он будет использовать простой SimplePagedResourceAssembler
(внутренний класс PRA
) для преобразования отдельных элементов страницы во вложенных Resource
экземпляров.
чтобы настроить это, 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);
Outlook
по состоянию на предстоящую весну Data Commons 1.7 RC1 (и Spring HATEOAS 0.9 транзитивно)prev
и next
ссылки будут создаваться как RFC6540 совместимые шаблоны URI для предоставления параметров запроса разбиения на страницы, настроенных в HandlerMethodArgumentResolvers
for Pageable
и Sort
.
в конфигурация, показанная выше, может быть упрощена путем аннотирования класса config с помощью @EnableSpringDataWebSupport
что позволит вам избавиться от всех явных объявлений bean.
АЛЬТЕРНАТИВНЫЙ СПОСОБ
другой способ-использовать HTTP-заголовок диапазона (подробнее в RFC 7233). Вы можете определить заголовок HTTP следующим образом:
Range: resources=20-41
это означает, что вы хотите получить ресурс от 20 до 41 (включая). Этот способ позволяет consuments API получать точно определенные ресурсы.
Это просто альтернативный способ. Диапазон часто используется с другими единицами (например, байтами и т. д.)
рекомендуется Путь
если вы хотите работать с разбиением на страницы и иметь действительно применимый API (гипермедиа / HATEOAS включены), то я рекомендую добавить страницу и PageSize к вашему URL. Пример:
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; }
}