Выбрать главу

Любые endpoint, которые вы определяете в своих собственных контроллерах, не будут автоматически включены в качестве гиперссылок в ресурсы, возвращаемые endpoint Spring Data REST. Это означает, что клиенты не смогут обнаружить ваши пользовательские endpoint  с именем отношения.

Давайте сначала обратимся к проблеме базового пути. Spring Data REST включает в себя @RepositoryRestController, новую аннотацию для аннотирования классов контроллеров, чьи отображения должны принимать базовый путь, который совпадает с тем, который настроен для endpoint Spring Data REST. Проще говоря, все сопоставления в контроллере, помеченном @RepositoryRestController, будут иметь свой путь с префиксом со значением свойства spring.data.rest.base-path (которое вы настроили как / api).

Вместо того, чтобы воскрешать DesignTacoController, в котором было несколько методов-обработчиков, которые вам не нужны, вы создадите новый контроллер, который содержит только метод recentTacos(). RecentTacosController в следующем листинге помечен аннотацией @RepositoryRestController для принятия базового пути Spring Data REST для его сопоставлений запросов (для request mapping).

Листинг 6.7. Применение базового пути Spring Data REST к контроллеру

package tacos.web.api;

import static org.springframework.hateoas.mvc.ControllerLinkBuilder.*;

import java.util.List;

import org.springframework.data.domain.PageRequest;

import org.springframework.data.domain.Sort;

import org.springframework.data.rest.webmvc.RepositoryRestController;

import org.springframework.hateoas.Resources;

import org.springframework.http.HttpStatus;

import org.springframework.http.ResponseEntity;

import org.springframework.web.bind.annotation.GetMapping;

import tacos.Taco;

import tacos.data.TacoRepository;

 

@RepositoryRestController

public class RecentTacosController {

   private TacoRepository tacoRepo;

   public RecentTacosController(TacoRepository tacoRepo) {

       this.tacoRepo = tacoRepo;

   }

 

   @GetMapping(path="/tacos/recent", produces="application/hal+json")

   public ResponseEntity<Resources<TacoResource>> recentTacos() {

       PageRequest page = PageRequest.of(

           0, 12, Sort.by("createdAt").descending());

       List<Taco> tacos = tacoRepo.findAll(page).getContent();

       List<TacoResource> tacoResources = new TacoResourceAssembler().toResources(tacos);

       Resources<TacoResource> recentResources = new Resources<TacoResource>(tacoResources);

       recentResources.add(

           linkTo(methodOn(RecentTacosController.class).recentTacos())

       .withRel("recents"));

       return new ResponseEntity<>(recentResources, HttpStatus.OK);

   }

}

Несмотря на то, что @GetMapping сопоставляется с путем /tacos/recent, аннотация @RepositoryRestController на уровне класса гарантирует, что к нему будет добавлен базовый путь Spring Data REST. Метод recentTacos() будет обрабатывать запросы GET для /api/tacos/recent.

Важно отметить, что хотя @RepositoryRestController назван так же, как @RestController, он не обладает той же семантикой, что и @RestController. В частности, он не гарантирует, что значения, возвращаемые из методов-обработчиков, автоматически записываются в тело ответа. Поэтому вам нужно либо аннотировать метод с помощью @ResponseBody, либо возвращать ResponseEntity, который оборачивает данные ответа. Здесь решили вернуть ResponseEntity.

При использовании RecentTacosController в запросах на /api/tacos/recent будет возвращено до 15 самых последних созданных тако без необходимости разбивать на страницы и сортировать параметры в URL-адресе. Но он все еще не появляется в списке гиперссылок при запросе /api/tacos. Давайте исправим это.

6.3.4 Добавление пользовательских гиперссылок в endpoint Spring Data

Если endpoint недавно созданных тако не входит в число гиперссылок, возвращаемых из /api/tacos, как клиент будет знать, как получить самые последние тако? Он должен либо угадать, либо использовать параметры страницы и сортировки. В любом случае, это будет жестко закодировано в клиентском коде, что не идеально.

Однако, объявив ресурс обработчик bean-компонентов (resource processor bean), вы можете добавить ссылки в список ссылок Spring Data REST. Spring Data HATEOAS предлагает ResourceProcessor, интерфейс для управления ресурсами до их возврата через API. Для ваших целей вам нужна реализация ResourceProcessor, которая добавляет recents ссылку на любой ресурс типа PagedResources<Resource<Taco> > (тип, возвращаемый для /api/tacos endpoint). В следующем листинге показан метод объявления bean-компонента, определяющий ResourceProcessor.

Листинг 6.8. Добавление пользовательских ссылок в REST Spring Data endpoint

@Bean

public ResourceProcessor<PagedResources<Resource<Taco>>>

       tacoProcessor(EntityLinks links) {

   return new ResourceProcessor<PagedResources<Resource<Taco>>>() {

       @Override

       public PagedResources<Resource<Taco>> process(

               PagedResources<Resource<Taco>> resource) {

           resource.add(

               links.linkFor(Taco.class)

               .slash("recent")

               .withRel("recents"));

           return resource;

       }

   };

}

ResourceProcessor, показанный в листинге 6.8, определяется как анонимный внутренний класс и объявляется как bean-компонент, создаваемый в контексте приложения Spring. Spring HATEOAS обнаружит этот bean-компонент (как и любые другие bean-компоненты типа ResourceProcessor) автоматически и применяет их к соответствующим ресурсам. В этом случае, если из контроллера возвращается PagedResources<Resource<Taco>>, он получит ссылку на самые последние созданные тако. Это включает в себя ответ на запросы для /api/tacos.