Spring MVC, REST и HATEOAS
Я изо всех сил стараюсь внедрить службы Spring MVC 3.x RESTful с 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 содержал простую ссылку "self", которую клиент может использовать для обновления объекта, удаления его или чего-то еще. У него также может быть ссылка "друзей", указывающая, как получить список пользователей:
{
firstName: "John",
lastName: "Smith",
links: [
{
rel: "self",
ref: "http://myserver/users/1"
},
{
rel: "friends",
ref: "http://myserver/users/1/friends"
}
]
}
Как-то я хочу привязать ссылки к моему объекту. Я считаю, что правильное место для этого - в уровне контроллера, поскольку все контроллеры знают правильные URL-адреса. Кроме того, поскольку я поддерживаю несколько представлений, я чувствую, что все правильно, это как-то украсить объекты моего домена в контроллере, прежде чем они будут преобразованы в JSON/XML/что угодно в рамки разрешения w760. Один из способов сделать это может заключаться в том, чтобы связать POJO с общим классом ресурсов, который содержит список ссылок. Для того, чтобы хрустнуть в формат, который я хочу, потребуется некоторое изменение настроек, но его выполнимость. К сожалению, вложенные ресурсы не могут быть обернуты таким образом. Другие вещи, которые приходят на ум, включают добавление ссылок на ModelAndView, а затем настройку каждого из Spring готовых решений для отображения ссылок на созданный JSON/XML/и т.д. Я не хочу постоянно обрабатывать JSON/XML и т.д. для размещения различных ссылок, когда они приходят и уходят в процессе развития.
Мысли?
Ответы
Ответ 1
В GitHub есть полезный проект под названием Spring HATEOAS, который имеет следующее описание:
"Этот проект предоставляет некоторые API для облегчения создания представлений REST которые следуют принципу HATEOAS при работе с Spring и особенно Spring 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
Ответ 2
Мои мысли:
- используя какое-то соглашение об именах, так что, например, собственный ссылочный url может быть построен из имени класса объекта.
- Я не думаю, что добавление материалов ссылок должно быть добавлено контроллером (кстати, вы сами писали "Я не хочу, чтобы мои контроллеры были загрязнены конструкциями представлений". Я попытался бы найти способ расширить сериализацию JSON так что он автоматически добавит дополнительные материалы. Может потребоваться добавить некоторые аннотации к вашим объектам, даже если это немного их загрязнит.
Ответ 3
Просто наткнулся на это, ища что-то еще и подумал, что вы должны рассматривать использование заголовка Link вместо содержимого в теле JSON, которое действительно просто загрязняет представления ваших ресурсов.
Обратите внимание на заметку IETFs на веб-ссылку, а также реестр IANA отношений связи.
Ответ 4
Чтобы создать ссылку в REST
api, вы можете использовать проект HAETOAS
структуры Spring.
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
), которое вы можете установить в entity
Object
.