在Spring Data REST中如何覆盖PATCH方法

3
我希望用自己的控制器覆盖spring-data-rest中资源的PATCH方法。我目前有以下代码:
@RepositoryRestResource
interface ItemRepository extends JpaRepository<Item, Long> {
}

@RepositoryRestController
@Slf4j
class ItemController {

    @Autowired
    private ItemRepository itemRepository;

    @PatchMapping("/items/{id}")
    public void updateItem(@PathVariable("id") Long id, @RequestBody ItemDTO itemDTO) {
        log.info("Updating item {}", id);
        Item found = itemRepository.findOne(id);
        found.name = itemDTO.name;
        itemRepository.save(found);
    }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class ItemDTO {
    String name;
}

我可以通过调用以下命令来创建一个项目:

curl -X POST \ http://localhost:8080/items \ -H 'Content-Type: application/json' \ -d '{ "name" : "anItem" }'

但是,如果我尝试使用 PATCH 更新项目,如下所示:

curl -X PATCH \ http://localhost:8080/items/1 \ -H 'Content-Type: application/json' \ -d '{ "name" : "update" }'

请求将由我的控制器处理,但应用程序也会抛出此堆栈跟踪并响应状态码400。

2018-02-27 16:58:55.510 ERROR 16112 --- [o-auto-1-exec-1] o.s.d.r.w.RepositoryRestExceptionHandler : I/O error while reading input message; nested exception is java.io.IOException: Stream closed

        org.springframework.http.converter.HttpMessageNotReadableException: I/O error while reading input message; nested exception is java.io.IOException: Stream closed
        at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:229) ~[spring-webmvc-4.3.14.RELEASE.jar:4.3.14.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:150) ~[spring-webmvc-4.3.14.RELEASE.jar:4.3.14.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:128) ~[spring-webmvc-4.3.14.RELEASE.jar:4.3.14.RELEASE]
        at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
        at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:158) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) ~[spring-webmvc-4.3.14.RELEASE.jar:4.3.14.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.14.RELEASE.jar:4.3.14.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.14.RELEASE.jar:4.3.14.RELEASE]
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.14.RELEASE.jar:4.3.14.RELEASE]
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) ~[spring-webmvc-4.3.14.RELEASE.jar:4.3.14.RELEASE]
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) ~[spring-webmvc-4.3.14.RELEASE.jar:4.3.14.RELEASE]
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.14.RELEASE.jar:4.3.14.RELEASE]
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843) ~[spring-webmvc-4.3.14.RELEASE.jar:4.3.14.RELEASE]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.27.jar:8.5.27]

我在这里创建了一个示例项目(带有演示错误的测试):https://github.com/JanRenkin/springdatarest

一些 shell 和 curl 的组合在引号方面的行为不如预期,以下是我在 Linux 和 Windows 终端上的经验:curl -X PATCH http://localhost:8080/items/1 -H "Content-Type: application/json" -d "{ \"name\" : \"update\" }" - Marc Tarin
2个回答

0

Fazel 是正确的。您必须使用 BasePathAwareController 来覆盖现有的默认 REST 实现。如果您想要添加其他端点,可以使用 @RepositoryRestController,但由于 /items/{id} 已经存在于默认情况下(因为在您的 repo 类上有 @RepositoryRestResource),所以您不能这样做。

这里发生的情况是两个实现都被调用了,这会导致流错误,因为您只能从流中读取一次。流被 ItemController 消耗,因此当默认实现尝试从中读取时,它无法读取。


0
通过使用@BasePathAwareController注释,您可以重写Spring Data Rest路径的默认实现。为避免出现错误,您的方法应该返回该实体。
@BasePathAwareController
@Slf4j
class ItemController {

@Autowired
private ItemRepository itemRepository;

@PatchMapping("/items/{id}")
public ResponseEntity<Item> updateItem(@PathVariable("id") Long id, @RequestBody 
ItemDTO itemDTO) {
    log.info("Updating item {}", id);
    Item found = itemRepository.findOne(id);
    found.name = itemDTO.name;
    Item savedItem =itemRepository.save(found);
    return new ResponseEntity<>(savedItem , HttpStatus.OK);
}

}


OP使用RepositoryRestController,它继承自BasePathAwareController - Marc Tarin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接