Сопоставление URI HAL в @RequestBody с управляемым объектом Spring Data Rest

Я использую Spring Data JPA для управления объектом JPA, а Spring Data Rest экспортирует репозиторий в REST API.

Я также создаю настраиваемый контроллер, в котором я хочу взять URI объекта (ссылка HAL) и автоматически сопоставить его с объектом объекта через CrudRepository.

CustomController

@RequestMapping(path = MeLinks.ELEVATE, method = RequestMethod.PUT, consumes = RestMediaTypes.TEXT_URI_LIST_VALUE)
HttpEntity<?> elevate(@RequestBody @Valid CollectionModel<Contact> contact) {
    ...
}

При попытке передать PUT контактную ссылку, такую ​​как http://localhost:8080/contacts/1, с типом содержимого text/uri-list, я могу получить доступ к ссылке, используя contact.getLinks(), но не сам объект «Контакт».

Может ли Spring Data Rest автоматически определять сущность из URI? Мне известно о встроенном UriToEntityConverter, но как мне его использовать?

Редактировать

Вот попытка, которая работает, но на самом деле не решает проблему изящно.

Код ниже инициализирует UriToEntityConverter и преобразует входящий URI в объект домена.

@Autowired
private ApplicationContext applicationContext;

@Autowired
private MappingContext<?, ?> mappingContext;

@RequestMapping(path = MeLinks.ELEVATE, method = RequestMethod.PUT, consumes = RestMediaTypes.TEXT_URI_LIST_VALUE)
HttpEntity<?> elevate(@RequestBody @Valid CollectionModel<Contact> uris) {

    URI uri = URI.create(uris.getLinks().get(0).getHref());

    Repositories repositories = new Repositories(applicationContext);

    PersistentEntity<?,?> contactPersistentEntity = repositories.getPersistentEntity(Contact.class);

    UriToEntityConverter uriToEntityConverter = new UriToEntityConverter(
        new PersistentEntities(Collections.singleton(mappingContext)), 
        new DefaultRepositoryInvokerFactory(repositories), 
        repositories);

    Contact t = (Contact) uriToEntityConverter.convert(uri, TypeDescriptor.valueOf(URI.class), TypeDescriptor.valueOf(Contact.class));
}

Как вы понимаете, получить объект домена из Repository было бы намного проще, чем делать выше. Также это работает, если URI использует ID как уникальную часть ссылки. В моем случае я настроил его для использования вместо этого UUID. Таким образом, поведение UriToEntityConverter по умолчанию работать не будет.

ПРИМЕЧАНИЕ: Resources от класса был переименован до CollectionModel с первым выпуском HATEOAS.

Работает для меня, но, к сожалению, это не работает для дочерних сущностей (например, http://localhost:8080/contacts/1/childEntity). Я поискал и пока ничего не нашел.

GuiRitter 06.04.2018 14:38

@GuiRitter, что именно не работает для дочерних сущностей? Есть ли у дочернего объекта репозиторий или это настраиваемая ссылка? В случае пользовательской ссылки, вы используете RepositoryRestController?

xsreality 07.04.2018 20:04

В приведенном выше примере ссылки он пытается проанализировать childEntity как Long, как если бы это был идентификатор contact, я полагаю. У childEntity есть репозиторий, но нет настраиваемой ссылки.

GuiRitter 09.04.2018 14:25

Ах я вижу. Это может быть связано с тем, что UriToEntityConverter предназначен для анализа только корневых URI. Итак, в вашем случае URI для синтаксического анализа должен быть http://localhost:8080/child_entities/1 или аналогичным.

xsreality 10.04.2018 13:40

Я пытаюсь использовать ваш код, но как получить @Autowired private MappingContext <?,?> MappingContext ;?

erotsppa 06.11.2019 22:01

Autowiring MappingContext <?,?> У меня работает

Cubimon 27.05.2020 14:37
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
6
856
1

Ответы 1

Если вы хотите продолжать использовать UriToEntityConverter, я рекомендую проверить эта часть документации Spring Data REST, чтобы настроить URI ресурса на другое свойство с помощью класса EntityLookupSupport<T>. После этого UriToEntityConverter должен правильно вернуть объект.

Если вы хотите использовать репозиторий напрямую, как вы заявили, примите во внимание следующее:

Если посмотреть на исходный код UriToEntityConverter, он использует последнюю часть URI в качестве идентификатора объекта. Ты тоже можешь это сделать. (В этом фрагменте кода я только что изменил ваш код сверху, предполагая, что вы правильно получили объект URI)

private ContactRepository contactRepository;

// You should use constructor injection, as it is preferred over field injection.
@Autowired
public CustomController(ContactRepository contactRepository){
    this.contactRepository = contactRepository;
}


@RequestMapping(path = MeLinks.ELEVATE, method = RequestMethod.PUT, consumes = RestMediaTypes.TEXT_URI_LIST_VALUE)
HttpEntity<?> elevate(@RequestBody @Valid CollectionModel<Contact> uris) {
    URI uri = URI.create(uris.getLinks().get(0).getHref());

    Optional<Contact> optionalContact = contactRepository.findByName(getLastUriPart(uri));

    if (optionalContact.isPresent()){
        return optionalContact.get();
    } else {
        // Error handling
    }
}

private String getLastUriPart(URI uri) {
    String[] uriParts = uri.getPath().split("/");

    if (uriParts.length < 2) {
        // Error handling
    }

    return uriParts[uriParts.length - 1];
}

Другие вопросы по теме