Я использую 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.
@GuiRitter, что именно не работает для дочерних сущностей? Есть ли у дочернего объекта репозиторий или это настраиваемая ссылка? В случае пользовательской ссылки, вы используете RepositoryRestController?
В приведенном выше примере ссылки он пытается проанализировать childEntity как Long, как если бы это был идентификатор contact, я полагаю. У childEntity есть репозиторий, но нет настраиваемой ссылки.
Ах я вижу. Это может быть связано с тем, что UriToEntityConverter предназначен для анализа только корневых URI. Итак, в вашем случае URI для синтаксического анализа должен быть http://localhost:8080/child_entities/1 или аналогичным.
Я пытаюсь использовать ваш код, но как получить @Autowired private MappingContext <?,?> MappingContext ;?
Autowiring MappingContext <?,?> У меня работает





Если вы хотите продолжать использовать 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];
}
Работает для меня, но, к сожалению, это не работает для дочерних сущностей (например,
http://localhost:8080/contacts/1/childEntity). Я поискал и пока ничего не нашел.