2011-08-23 7 views
22

Я борюсь с правильным способом реализации Spring MVC 3.x RESTful сервисов с HATEOAS. Рассмотрим следующие ограничения:Spring MVC, REST и HATEOAS

  • Я не хочу, чтобы мои объекты домена загрязнялись конструкциями web/rest.
  • Я не хочу, чтобы мои контроллеры были загрязнены конструкциями вида.
  • Я хочу поддерживать несколько видов.

В настоящее время у меня есть хорошее приложение MVC без HATEOAS. Объекты домена - это чистые POJO без каких-либо взглядов или встроенных понятий web/rest. Например:

class User { 
    public String getName() {...} 
    public String setName(String name) {...} 
    ... 
} 

Мои контроллеры также просты. Они обеспечивают маршрутизацию и статус, а также делегируют платформу разрешения взглядов Spring. Обратите внимание, мое приложение поддерживает JSON, XML и HTML, но не сущности домена или контроллеры не имеют встроенный просматривать информацию:

@Controller 
@RequestMapping("/users") 
class UserController { 

    @RequestMapping 
    public ModelAndView getAllUsers() { 
    List<User> users = userRepository.findAll(); 
    return new ModelAndView("users/index", "users", users); 
    } 

    @RequestMapping("/{id}") 
    public ModelAndView getUser(@PathVariable Long id) { 
    User user = userRepository.findById(id); 
    return new ModelAndView("users/show", "user", user); 
    } 
} 

Итак, теперь мой вопрос - я не уверен в чистом виде для поддержки HATEOAS. Вот пример. Скажем, когда клиент запрашивает пользователя в формате JSON, то выходит так:

{ 
    firstName: "John", 
    lastName: "Smith" 
} 

Давайте также сказать, что, когда я поддерживаю HATEOAS, я хочу, чтобы JSON, чтобы содержать простое «я» ссылку, что клиент может затем использовать, чтобы обновить объект, удалить его или что-то еще. Это может также иметь «друзей» ссылку, указывающую, как получить список пользователя друзей:

{ 
    firstName: "John", 
    lastName: "Smith", 
    links: [ 
    { 
     rel: "self", 
     ref: "http://myserver/users/1" 
    }, 
    { 
     rel: "friends", 
     ref: "http://myserver/users/1/friends" 
    } 
    ] 
} 

Как-то я хочу, чтобы прикрепить ссылки на мой объект. Я считаю, что правильное место для этого - в уровне контроллера, поскольку все контроллеры знают правильные URL-адреса. Кроме того, поскольку я поддерживаю несколько представлений, я чувствую, что это правильно, так это как-то украсить объекты домена в контроллере, прежде чем они будут преобразованы в JSON/XML/независимо от структуры разрешения представления Spring. Один из способов сделать это может заключаться в том, чтобы связать POJO с общим классом ресурсов, который содержит список ссылок. Для того, чтобы хрустнуть в формат, который я хочу, потребуется некоторое изменение настроек, но его выполнимость. К сожалению, вложенные ресурсы не могут быть обернуты таким образом. Другие вещи, которые приходят на ум, включают добавление ссылок на ModelAndView, а затем настройку каждого из готовых редакторов Spring's, чтобы заполнить ссылки в сгенерированный JSON/XML/и т. Д. Я не хочу постоянно обрабатывать JSON/XML и т. Д. для размещения различных ссылок, когда они приходят и уходят в процессе развития.

Мысли?

+2

В настоящее время проект Spring Data называется [Spring Data - Rest] (http://www.springsource.org/spring-data/rest), который поддерживает HATEOAS в той или иной форме. – SingleShot

+1

или вы можете использовать автономный модуль [spring-hateoas] (https://github.com/SpringSource/spring-hateoas). – Mariusz

ответ

10

Существует полезный проект под названием Spring HATEOAS на GitHub, который имеет следующее описание:

«Этот проект предусматривает некоторые API-интерфейсы для облегчения создания REST представлений , которые следуют принципу HATEOAS при работе с весной и особенно весной MVC»

Если класс ресурса вы возвращаете распространяется„ResourceSupport“вы можете легко добавить ссылки на него, и вы можете построить ссылки, используя„ControllerLinkBuilder“, например, добавить ссылку сам:

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

Link link = linkTo(YourController.class).slash(resource.getName()).withSelfRel(); 
resource.add(link); 

Это совершенно новый проект, но он доступен из публичного Maven репо, если это необходимо:

<dependency> 
    <groupId>org.springframework.hateoas</groupId> 
    <artifactId>spring-hateoas</artifactId> 
    <version>0.3.0.RELEASE</version> 
</dependency> 

Если вы используете Maven артефакт:

org.sfw.hateoas.mvc.ControllerLinkBuilder 

становится:

org.springframework.hateoas.mvc.ControllerLinkBuilder 
+0

Интересно. Я предпочитаю импортировать Spring и другой инфраструктурный код на периферию моего приложения, но в этом случае все классы ресурсов, расширяющие 'ResourceSupport', кажутся приличным компромиссом. Благодаря! – SingleShot

+2

О, и его от Оливера Гирке, который является главным парнем данных Spring. Круто. – SingleShot

+0

Я написал сообщения в блоге, связанные с [HATEOAS using Spring Framework] (http://azagorneanu.blogspot.com/2013/06/hateoas-using-spring-framework.html) –

1

Мои мысли:

  • с использованием своего рода именования, так что, например, само URL ссылки могут быть построены из имени класса объекта.
  • Я не думаю, что добавление компонентов ссылок должно быть добавлено контроллером (кстати, вы сами писали «Я не хочу, чтобы мои контроллеры были загрязнены конструкциями представлений». Я попытался бы найти способ расширить сериализацию JSON так что он автоматически добавит дополнительные материалы. Может потребоваться добавить некоторые аннотации к вашим объектам, даже если это их немного загрязнит.
+1

Спасибо. Соглашение об именах могло бы работать, если бы все, что я хотел, было ссылкой «я», однако в реальном приложении было бы несколько ссылок на объекты, связанные с рабочим процессом (похожие на несколько знаменитые [«как получить чашку кофе»] (http://www.infoq.com/articles/webber-rest-workflow), которая не может быть создана по соглашению. – SingleShot

+0

Что касается генерации ссылок - мне нужно придумать что-то несколько общее, поэтому, когда я добавляю новую ссылку, мне не нужно редактировать мои 3 разных разрешения представления (JSON/XML/HTML). Хммм.Возможно, природа архитектуры RESTful с этим стеком технологий требует, чтобы объекты домена были «загрязнены» ссылками, и, может быть, это не так ... – SingleShot

+2

«Соглашение об именах» - плохая идея. В частности, он кажется полностью анти-HATEOAS. Точка HATEOAS заключается в том, что клиенту не нужно «знать» ваш API, но он может просто следовать ссылкам, чтобы перейти к другому переходу объекта или состояния. – HDave

1

Просто наткнулся на это, ища что-то еще и подумал, что вы должны рассматривать использование заголовка Link вместо содержимого в теле JSON, которое действительно просто загрязняет представления ваших ресурсов.

Проверьте IETFs memo on web linking, а также IANA registry of link relations.

0

Чтобы создать ссылку в ваш REST api вы можете использовать HAETOAS проект весной рамки.

org.springframework.hateoas.mvc.ControllerLinkBuilder класса имеет множество метод, который можно использовать для создания ссылки, как -

Link link=linkTo(PersonControllerImpl.class).slash(null).withSelfRel(); 

Кроме того, если у вас есть метод контроллера, имеющий @RequestMapping аннотации с некоторым значением URI -

@RequestMapping(value = "/customer", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_VALUE}) 
    public ResponseEntity<?> getCustomer() { 

//... 
} 

затем вы можете создать ссылку, используя значение URI метода, как -

linkTo(methodOn(PersonControllerImpl.class).getCustomer()).toUri().toString() 

он вернет String значение (http://www.urhost.com/customer), которое вы можете установить в своем entityObject.

Смежные вопросы