Spring 获得 link 实体
Spring get link to an entity
我正在使用 Spring-boot-starter-data-jpa,在我的 RestController 中我想 return 新创建对象的位置。有没有办法反转@RequestMapping 而不是硬编码如何构建 URL?
@RestController
@ExposesResourceFor(BookInstance.class)
public class BookInstanceController {
@RequestMapping(value="/bookInstances", method=RequestMethod.POST)
ResponseEntity<BookInstance> createBookInstance(@RequestBody BookInstance bookInstance){
BookInstance createdBookInstance = bookInstanceRepository.save(bookInstance);
return ResponseEntity.created(**reverseURL(createdBookInstance)**);
// return new ResponseEntity<BookInstance>(createdBookInstance, HttpStatus.CREATED);
// return createdBookInstance;
}
}
我总是看到人们在这个函数中硬编码他们的 URL 构造,这让我无话可说......
当然我也有同样的GET函数class(否则就没有什么可以反推的了)
@RequestMapping(value="/bookInstances/{id}", method=RequestMethod.GET)
ResponseEntity<?> findOne(@PathVariable("id") Long id){
BookInstance bookInstance = bookInstanceRepository.findOne(id);
if(bookInstance == null){
return ResponseEntity.notFound().build();
}
return new ResponseEntity<BookInstance>(bookInstance, HttpStatus.OK);
}
我通过将此添加到我的 class:
解决了这个问题
@Autowired EntityLinks entityLinks;
并使用 Spring 的一些 HATEOAS 功能。
Link link = entityLinks.linkToSingleResource(BookInstance.class, createdBookInstance.getId()).expand();
return ResponseEntity.created(URI.create(link.getHref())).build();
注意:在上面几行中,createdBookInstance只是在数据库中创建记录后返回对象。
使用资源汇编程序的替代解决方案:
public class BookInstanceResource extends Resource<BookInstance> {
public BookInstanceResource(Book content, Link... links) {
super(content, links);
}
}
public class BookInstanceResourceAssembler extends ResourceAssemblerSupport<BookInstance, BookInstanceResource> {
public BookInstanceResourceAssembler() {
super(BookInstanceController.class, BookInstanceResource.class)
}
@Override
public BookInstanceResource toResource(BookInstance bookInstance) {
// linkTo requires the following static import:
// import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
ControllerLinkBuilder builder = linkTo(BookInstance.class).slash("bookInstances").slash(bookInstance);
return new BookInstanceResource(bookInstance,
builder.withSelfRel(),
builder.withRel("bookInstance");
}
}
在你的控制器中class:
@Autowired
private BookInstanceResourceAssembler resourceAssembler;
@GetMapping(value = "/bookInstances/{id}")
ResponseEntity findOne(@PathVariable("id") Long id) {
BookInstance bookInstance = bookInstanceRepository.findOne(id);
if(bookInstance == null){
return ResponseEntity.notFound().build();
}
BookInstanceResource resource = resourceAssembler.toResource(bookInstance);
return ResponseEntity.created(URI.create(resource.getLink("self").getHref()))
.body(resource);
}
由于其他解决方案与我的源代码不兼容,我费了好大劲才找到 return 新创建的实体访问 URL 的解决方案 API。我个人觉得@EralpB 解决方案很简单。但是,我在创建 Link 时遇到了内部使用的 SimpleEntityPlugin 问题。
最后,我找到了带有简单代码的解决方案,我不会使用任何此类 Hateoas API。我不确定这个解决方案是否与 Spring 兼容,但我在 SpringBoot-2.x 版本中尝试过。它对我来说很好用。
@PostMapping("/students")
public ResponseEntity<Object> createStudent(@RequestBody Student student) {
Student savedStudent = studentRepository.save(student);
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}")
.buildAndExpand(savedStudent.getId()).toUri();
return ResponseEntity.created(location).build();
}
根据上面的示例,URL 将 return 类似于 http://localhost:8080/students/1。这可能因您的配置而异。
如果您需要在 URL 中的 students 旁边和 id 之前添加任何额外的路径,您可以直接在 {id} 声明之前硬编码,例如 /search/{id}。所以实际的 URL 看起来像 http://localhost:8080/students/search/1
如果以防万一,您没有将学生配置为按 ID 搜索学生的一部分,并且配置了一些其他路径以按 ID 访问学生,则可以使用以下代码仅加载上下文,例如路径 http://localhost:8080 并将 hardcode/load 从属性添加到 uri。
URI location = ServletUriComponentsBuilder.fromCurrentContextPath().path("/search/{id}")
.buildAndExpand(newCase.getCaseId()).toUri();
根据上面的代码片段,returning URL 看起来像 http://localhost:8080/search/1. You can explore different methods available under the ServletUriComponentsBuilder。我希望这会很清楚。
要轻松获得正确的资源 link,您应该使用此答案 。
到return 不仅位置,而且新创建的资源,你可以采用这种方法:
import lombok.RequiredArgsConstructor;
import org.springframework.data.rest.webmvc.PersistentEntityResource;
import org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler;
import org.springframework.data.rest.webmvc.RepositoryRestController;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.server.EntityLinks;
import org.springframework.hateoas.server.ExposesResourceFor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import sk.qpp.qaron.user.repository.QaronUser;
import java.net.URI;
@RepositoryRestController
@ExposesResourceFor(BookInstance.class)
@RequiredArgsConstructor // lombok thing, autoviring all final attributes through ctor
public class BookInstanceController {
private final EntityLinks entityLinks;
@RequestMapping(value="/bookInstances", method= RequestMethod.POST)
ResponseEntity<Object> createBookInstance(@RequestBody BookInstance bookInstance, PersistentEntityResourceAssembler resourceAssembler){
// save to database
final BookInstance createdBookInstance = bookInstanceRepository.save(bookInstance);
final PersistentEntityResource newEntityResource = resourceAssembler.toModel(createdBookInstance);
Link link = entityLinks.linkToItemResource(QaronUser.class, createdBookInstance.getId()).expand();
return ResponseEntity
.created(URI.create(link.getHref()))
.body(newEntityResource);
}
}
请注意,此示例使用 @RepositoryRestController
而不是 @RestController
。这对于连线 PersistentEntityResourceAssembler
而不是 java.lang.IllegalArgumentException: entities is marked non-null but is null
.
至关重要
我正在使用 Spring-boot-starter-data-jpa,在我的 RestController 中我想 return 新创建对象的位置。有没有办法反转@RequestMapping 而不是硬编码如何构建 URL?
@RestController
@ExposesResourceFor(BookInstance.class)
public class BookInstanceController {
@RequestMapping(value="/bookInstances", method=RequestMethod.POST)
ResponseEntity<BookInstance> createBookInstance(@RequestBody BookInstance bookInstance){
BookInstance createdBookInstance = bookInstanceRepository.save(bookInstance);
return ResponseEntity.created(**reverseURL(createdBookInstance)**);
// return new ResponseEntity<BookInstance>(createdBookInstance, HttpStatus.CREATED);
// return createdBookInstance;
}
}
我总是看到人们在这个函数中硬编码他们的 URL 构造,这让我无话可说......
当然我也有同样的GET函数class(否则就没有什么可以反推的了)
@RequestMapping(value="/bookInstances/{id}", method=RequestMethod.GET)
ResponseEntity<?> findOne(@PathVariable("id") Long id){
BookInstance bookInstance = bookInstanceRepository.findOne(id);
if(bookInstance == null){
return ResponseEntity.notFound().build();
}
return new ResponseEntity<BookInstance>(bookInstance, HttpStatus.OK);
}
我通过将此添加到我的 class:
解决了这个问题@Autowired EntityLinks entityLinks;
并使用 Spring 的一些 HATEOAS 功能。
Link link = entityLinks.linkToSingleResource(BookInstance.class, createdBookInstance.getId()).expand();
return ResponseEntity.created(URI.create(link.getHref())).build();
注意:在上面几行中,createdBookInstance只是在数据库中创建记录后返回对象。
使用资源汇编程序的替代解决方案:
public class BookInstanceResource extends Resource<BookInstance> {
public BookInstanceResource(Book content, Link... links) {
super(content, links);
}
}
public class BookInstanceResourceAssembler extends ResourceAssemblerSupport<BookInstance, BookInstanceResource> {
public BookInstanceResourceAssembler() {
super(BookInstanceController.class, BookInstanceResource.class)
}
@Override
public BookInstanceResource toResource(BookInstance bookInstance) {
// linkTo requires the following static import:
// import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
ControllerLinkBuilder builder = linkTo(BookInstance.class).slash("bookInstances").slash(bookInstance);
return new BookInstanceResource(bookInstance,
builder.withSelfRel(),
builder.withRel("bookInstance");
}
}
在你的控制器中class:
@Autowired
private BookInstanceResourceAssembler resourceAssembler;
@GetMapping(value = "/bookInstances/{id}")
ResponseEntity findOne(@PathVariable("id") Long id) {
BookInstance bookInstance = bookInstanceRepository.findOne(id);
if(bookInstance == null){
return ResponseEntity.notFound().build();
}
BookInstanceResource resource = resourceAssembler.toResource(bookInstance);
return ResponseEntity.created(URI.create(resource.getLink("self").getHref()))
.body(resource);
}
由于其他解决方案与我的源代码不兼容,我费了好大劲才找到 return 新创建的实体访问 URL 的解决方案 API。我个人觉得@EralpB 解决方案很简单。但是,我在创建 Link 时遇到了内部使用的 SimpleEntityPlugin 问题。
最后,我找到了带有简单代码的解决方案,我不会使用任何此类 Hateoas API。我不确定这个解决方案是否与 Spring 兼容,但我在 SpringBoot-2.x 版本中尝试过。它对我来说很好用。
@PostMapping("/students")
public ResponseEntity<Object> createStudent(@RequestBody Student student) {
Student savedStudent = studentRepository.save(student);
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}")
.buildAndExpand(savedStudent.getId()).toUri();
return ResponseEntity.created(location).build();
}
根据上面的示例,URL 将 return 类似于 http://localhost:8080/students/1。这可能因您的配置而异。
如果您需要在 URL 中的 students 旁边和 id 之前添加任何额外的路径,您可以直接在 {id} 声明之前硬编码,例如 /search/{id}。所以实际的 URL 看起来像 http://localhost:8080/students/search/1
如果以防万一,您没有将学生配置为按 ID 搜索学生的一部分,并且配置了一些其他路径以按 ID 访问学生,则可以使用以下代码仅加载上下文,例如路径 http://localhost:8080 并将 hardcode/load 从属性添加到 uri。
URI location = ServletUriComponentsBuilder.fromCurrentContextPath().path("/search/{id}")
.buildAndExpand(newCase.getCaseId()).toUri();
根据上面的代码片段,returning URL 看起来像 http://localhost:8080/search/1. You can explore different methods available under the ServletUriComponentsBuilder。我希望这会很清楚。
要轻松获得正确的资源 link,您应该使用此答案
到return 不仅位置,而且新创建的资源,你可以采用这种方法:
import lombok.RequiredArgsConstructor;
import org.springframework.data.rest.webmvc.PersistentEntityResource;
import org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler;
import org.springframework.data.rest.webmvc.RepositoryRestController;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.server.EntityLinks;
import org.springframework.hateoas.server.ExposesResourceFor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import sk.qpp.qaron.user.repository.QaronUser;
import java.net.URI;
@RepositoryRestController
@ExposesResourceFor(BookInstance.class)
@RequiredArgsConstructor // lombok thing, autoviring all final attributes through ctor
public class BookInstanceController {
private final EntityLinks entityLinks;
@RequestMapping(value="/bookInstances", method= RequestMethod.POST)
ResponseEntity<Object> createBookInstance(@RequestBody BookInstance bookInstance, PersistentEntityResourceAssembler resourceAssembler){
// save to database
final BookInstance createdBookInstance = bookInstanceRepository.save(bookInstance);
final PersistentEntityResource newEntityResource = resourceAssembler.toModel(createdBookInstance);
Link link = entityLinks.linkToItemResource(QaronUser.class, createdBookInstance.getId()).expand();
return ResponseEntity
.created(URI.create(link.getHref()))
.body(newEntityResource);
}
}
请注意,此示例使用 @RepositoryRestController
而不是 @RestController
。这对于连线 PersistentEntityResourceAssembler
而不是 java.lang.IllegalArgumentException: entities is marked non-null but is null
.