Spring mvc 将@RequestBody中的HAL URI映射到Spring数据Rest管理实体
我使用SpringDataJPA来管理JPA实体,SpringDataREST将存储库导出到RESTAPI中 我还构建了一个自定义控制器,希望在其中获取实体的URI(HAL链接),并通过Spring mvc 将@RequestBody中的HAL URI映射到Spring数据Rest管理实体,spring-mvc,spring-data,spring-data-rest,spring-hateoas,Spring Mvc,Spring Data,Spring Data Rest,Spring Hateoas,我使用SpringDataJPA来管理JPA实体,SpringDataREST将存储库导出到RESTAPI中 我还构建了一个自定义控制器,希望在其中获取实体的URI(HAL链接),并通过crudepository自动将其映射到实体对象 客户控制器 @RequestMapping(path=MeLinks.ELEVATE,method=RequestMethod.PUT,consumes=RestMediaTypes.TEXT\u URI\u LIST\u VALUE) HttpEntity提升(
crudepository
自动将其映射到实体对象
客户控制器
@RequestMapping(path=MeLinks.ELEVATE,method=RequestMethod.PUT,consumes=RestMediaTypes.TEXT\u URI\u LIST\u VALUE)
HttpEntity提升(@RequestBody@Valid CollectionModel联系人){
...
}
尝试放置联系人链接时,如http://localhost:8080/contacts/1
使用内容类型text/uri list
,我可以使用contact.getLinks()
访问链接,但不能使用contact对象本身
SpringDataREST是否可以从URI自动推断实体?我知道有一个内置的UriToEntityConverter
,但如何使用它呢
编辑
这是一个有效的尝试,但并不能很好地解决问题
下面的代码初始化一个UriToEntityConverter
,并将传入的URI转换为域对象
@Autowired
私有应用程序上下文应用程序上下文;
@自动连线
私有映射上下文映射上下文;
@RequestMapping(path=MeLinks.ELEVATE,method=RequestMethod.PUT,consumes=RestMediaTypes.TEXT\u URI\u LIST\u VALUE)
HttpEntity提升(@RequestBody@Valid CollectionModel URI){
URI=URI.create(uris.getLinks().get(0.getHref());
存储库存储库=新存储库(applicationContext);
PersistentEntity contactPersistentEntity=repositories.getPersistentEntity(Contact.class);
UriToEntityConverter UriToEntityConverter=新UriToEntityConverter(
新的PersistentEntity(Collections.singleton(mappingContext)),
新的DefaultRepositoryInvokerFactory(存储库),
储存库);
Contact t=(Contact)uriToEntityConverter.convert(uri,TypeDescriptor.valueOf(uri.class),TypeDescriptor.valueOf(Contact.class));
}
可以想象,从存储库
中获取域对象要比上述操作简单得多。假设URI使用ID
作为链接的唯一部分,这也是可行的。在我的例子中,我对它进行了定制,以使用UUID。因此,UriToEntityConverter
的默认行为将不起作用
注意:Resources
class toCollectionModel
,HATEOAS首次发布。如果您想继续使用UriToEntityConverter
我建议签出,使用EntityLookupSupport
类将资源URI自定义为不同的属性。然后,UriToEntityConverter
应正确返回实体
如果您希望直接使用存储库,请考虑以下内容:
查看的源代码,它使用URI的最后一部分作为对象的标识符。你也可以这样做。(在这个代码片段中,我刚刚从上面修改了您的代码,假设您正确地检索了URI
对象)
private ContactRepository ContactRepository;
//您应该使用构造函数注入,因为它优于字段注入。
@自动连线
公共CustomController(ContactRepository ContactRepository){
this.contactRepository=contactRepository;
}
@RequestMapping(path=MeLinks.ELEVATE,method=RequestMethod.PUT,consumes=RestMediaTypes.TEXT\u URI\u LIST\u VALUE)
HttpEntity提升(@RequestBody@Valid CollectionModel URI){
URI=URI.create(uris.getLinks().get(0.getHref());
可选选项contact=contactRepository.findByName(getLastUriPart(uri));
if(可选的contact.isPresent()){
返回optionalContact.get();
}否则{
//错误处理
}
}
私有字符串getLastUriPart(URI){
字符串[]uriParts=uri.getPath().split(“/”);
如果(长度小于2){
//错误处理
}
返回uriParts[uriParts.length-1];
}
适用于我,但太糟糕了,它不适用于子实体(例如http://localhost:8080/contacts/1/childEntity
)我四处搜索,到目前为止没有找到任何东西。@GuiRitter什么东西不适合子实体?子实体也有存储库还是自定义链接?在自定义链接的情况下,您是否使用RepositoryRestController
?在上面的示例链接中,它尝试将childEntity
解析为Long
,就好像它是联系人
id一样childEntity
确实有一个存储库,但没有自定义链接。啊,我明白了。这可能是因为UriToEntityConverter
仅用于解析根URI。因此,在您的例子中,要解析的URI应该是http://localhost:8080/child_entities/1
或类似内容。我正在尝试使用您的代码,但如何获取@Autowired private MappingContext MappingContext;?
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];
}