【问题标题】:Spring REST reuse nested requstmappingSpring REST 重用嵌套请求映射
【发布时间】:2017-04-08 11:52:48
【问题描述】:

我们有一个 REST API,用于一些 cmets。目前,最有趣的 URI 是:

GET /products/1/comments             // get all comments of product 1
GET /products/1/comments/5           // get the 5th comment of product 1
GET /products/1/comments/5/user      // get the user of the 5th comment
GET /products/1/comments/latest      // get the latest comment of product 1
GET /products/1/comments/latest/user // get the user of the latest comment

另外,可以直接访问cmets

GET /comments/987                    // get the comment with id 987
GET /comments/987/user               // get the user of comment with id 987

所以,我们有两个@RestController

@RestController
@RequestMapping("/products/{productId}")
public class ProductsCommentsResource {

    @GetMapping(value = "/comments")
    public ResponseEntity<?> getComments(@PathVariable Long productId){
       // get all products...
    }

    @GetMapping(value = "/comments/{commentNr}")
    public ResponseEntity<?> getComment(@PathVariable Long productId, @PathVaraible Long commentNr){
       // get comment with number commentNr of product productId
    }

    @GetMapping(value = "/comments/{commentNr}/user")
    public ResponseEntity<?> getCommentUser(@PathVariable Long productId, @PathVaraible Long commentNr){
       // get the user of comment with commentNr of productId
    }

    @GetMapping(value = "/comments/latest")
    public ResponseEntity<?> getLatestComment(@PathVariable Long productId){
       // get latest commentNr and call getComment(productId, commentNr)
    }

    @GetMapping(value = "/comments/latest/user")
    public ResponseEntity<?> getLatestCommentUser(@PathVariable Long productId){
       // get latest commentNr and call getCommentUser(productId, commentNr)
    }
}

@RestController
@RequestMapping("/comments")
public class CommentsResource {
    @GetMapping(value = "/{commentId}")
    public ResponseEntity<?> getComment(@PathVaraible Long commentId){
       // get comment id commentId
    }

    @GetMapping(value = "/{commentId}/user")
    public ResponseEntity<?> getCommentUser(@PathVaraible Long commendId){
       // get the user of comment with id commentId
    }
}      

因此latest 只是“获取最后一个commentNr 并使用此commentId 调用相应方法”的替换关键字

这只是一个摘录,除了用户,评论有大约 30 个子和子子资源(包括方法 POST、DELETE 等)。 因此,我们或多或少拥有三倍。

所以,很明显,我们需要改进这一点,删除重复的代码等。 这个想法是“封装” cmets-resources 并通过使用在课堂上注释的@RequestMapping 使其可重用。

我们想到了这样的机制:

  • /products/1/comments/latest/user 被调用
  • 调用被拦截,产品1的“最新”被解析为commentId
  • 呼叫将被重定向到```/cmets/{commendId}/user

因此,我们需要有一些重定向的东西 - /products/1/comments/latest[what ever]/comments/{commentId}[what ever] - /products/1/comments/5[what ever] 也转为 /comments/{commentId}[what ever]

和 /cmets/{commentId} 将是唯一的实现。

但是,我们在 spring 文档中没有找到任何合适的内容...

【问题讨论】:

    标签: java spring rest spring-mvc api-design


    【解决方案1】:

    您可以在控制器的@RequestMapping 中添加额外的 URL 路径前缀。

    @RequestMapping(value = { "/products/{productId}", "/" })
    

    这意味着您可以删除 CommentsResource 控制器并且您将能够访问相同的资源:

    /products/1/comments/5
    

    /comments/5
    

    例如,这里:

     @GetMapping(value = "/comments/{commentNr}")
        public ResponseEntity<?> getComment(@PathVariable Long productId, @PathVaraible Long commentNr){
           // get comment with number commentNr of product productId
        }
    

    明显的问题是productId 路径变量。如果您使用的是 Java 8,则可以使用 Optional 轻松解决:

    @GetMapping(value = "/comments/{commentNr}")
    public ResponseEntity<?> getComment(@PathVariable Optional<Long> productId, @PathVaraible Long commentNr){
        // get comment with number commentNr of product productId
        // Check whether productId exists
    }
    

    【讨论】:

    • 谢谢。一直认为路径变量不能是可选的。我试试看
    猜你喜欢
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    • 2021-12-15
    • 2012-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-24
    相关资源
    最近更新 更多