代码之家  ›  专栏  ›  技术社区  ›  Adam

Spring控制器RequestMapping路径变量中URL的零长度部分中断分辨率

  •  0
  • Adam  · 技术社区  · 6 年前

    我试图使应用程序的RESTAPI更为稳定,感觉我没有按预期的方式使用Spring请求映射。

    我有一个做阅读的GET端点:

    @RequestMapping(value = "thing/{thingName}",
            method = RequestMethod.GET,
            produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public String getThing(
            @PathVariable(value = "thingName", required = false)
                    String thingName,
            @RequestParam(value = "findByComponent", required = false)
                    String findByComponentQuery,
            @AuthenticationPrincipal User user) {
    ...
    

    为了更安全起见,我希望此端点同时执行以下两项操作:

    1. get/thing/thing name返回具有该名称的单个事物
    2. get/thing或/thing/with查询参数返回事物列表

    所以在我的控制器中,我可以测试 {thingName} 为空或零长度,如果是,请检查查询参数以了解已知的查询名称。

    不管怎么说 http://localhost:8080/thing/?findByComponent=component123 使用此日志从Spring返回404:

    12:45:18.485 PageNotFound : No mapping found for HTTP request with URI [/thing/] in DispatcherServlet with name 'dispatcher' : WARN : XNIO-1 task-3 : org.springframework.web.servlet.DispatcherServlet  
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   Justin Albano    6 年前

    弹簧不允许路径变量( {thingName} )映射到空 String . 实际上,这意味着 /thing/?findByComponent=component123 映射到 thing/{thingName} 空着 {TngNe} 但是,它希望有一些映射 thing . 因为没有映射到路径的终结点 事情 (不带路径变量),a 404 返回错误。

    要解决此问题,可以将此单端点拆分为两个单独的端点:

    @RequestMapping(value = "thing/{thingName}",
            method = RequestMethod.GET,
            produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public String getThing(
            @PathVariable(value = "thingName") String thingName,
            @AuthenticationPrincipal User user) {
        // ...
    }
    
    @RequestMapping(value = "thing",
            method = RequestMethod.GET,
            produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public String getThings(,
            @RequestParam(value = "findByComponent", required = false) String findByComponentQuery,
            @AuthenticationPrincipal User user) {
        // ...
    }
    

    有关详细信息,请参阅 With Spring 3.0, can I make an optional path variable? .

    这个 required=false 标志允许两种类型的请求:

    1. /thing
    2. /thing/<some_value>

    严格来说,包括URL结尾的尾随斜杠(即 /thing/ )表示已决定包含路径变量的值,但未提供任何值。在RESTAPI的上下文中, /事物/ 是两个不同的端点,后者意味着期望尾随斜杠后面的值。

    不必创建三个单独的请求映射(上面的每种情况都有一个)的解决方法是设置 @RequestMapping 控制器到基路径的值,然后具有 "" "/{thingName} 两个端点的请求映射:

    @RestController
    @RequestMapping("thing")
    public class ThingController {
    
        @RequestMapping(value = "/{thingName}",
                method = RequestMethod.GET,
                produces = MediaType.APPLICATION_JSON_VALUE)
        @ResponseBody
        public String getThing(
                @PathVariable(value = "thingName") String thingName) {
            return "foo";
        }
    
        @RequestMapping(value = "",
                method = RequestMethod.GET,
                produces = MediaType.APPLICATION_JSON_VALUE)
        @ResponseBody
        public String getThings(
                @RequestParam(value = "findByComponent", required = false) String findByComponentQuery) {
            return "bar";
        }
    }
    

    在这种情况下,将发生以下映射:

    1. : getThings
    2. /事物/ : 获得事物
    3. /thing/foo : getThing

    这个解决方法的一个例子,包括测试用例可以 found here .