如果@PathVariable找不到,它能返回null吗?

35

如果路径中没有定义路径变量,那么是否可能使@PathVariable返回null?否则我需要创建两个处理程序。一个用于/simple,另一个用于/simple/{game},但两者都是相同的,只有在未定义游戏参数时才从列表中选择第一个,然而如果定义了游戏参数,则使用它。

@RequestMapping(value = {"/simple", "/simple/{game}"}, method = RequestMethod.GET)
public ModelAndView gameHandler(@PathVariable("example") String example,
            HttpServletRequest request) {

当我尝试打开页面/simple时,出现以下错误:

原因是:java.lang.IllegalStateException: 在@RequestMapping中找不到@PathVariable [example]

6个回答

43

它们不能是可选的。如果您需要这样做,您需要两种方法来处理它们。

这反映了路径变量的本质 - 对于它们为空并不真正有意义。 REST风格的URL始终需要完整的URL路径。如果您有一个可选的组件,请考虑将其作为请求参数处理(即使用@RequestParam)。这更适合可选参数。


4
然而,自 v4.3.3 版本起,Spring 支持使用 @PathVariable(value = "siteId", required = false) String siteId 注解。尽管我没有找到不提供路径变量或将其留空的方法。 - Alex
2
@Alex 虽然可以将 required 参数设置为 false,但仍需要提供路径参数,否则会抛出异常。 - securecurve

41

正如其他人已经提到的那样,当您明确指定路径参数时,不能期望它们为null。但是,您可以尝试以下操作作为解决方法 -

@RequestMapping(value = {"/simple", "/simple/{game}"}, method = RequestMethod.GET)
public ModelAndView gameHandler(@PathVariable Map<String, String> pathVariablesMap,
            HttpServletRequest request) {
    if (pathVariablesMap.containsKey("game")) {
        //corresponds to path "/simple/{game}"
    } else {
        //corresponds to path "/simple"
    }           
}

如果您正在使用Spring 4.1和Java 8,则可以使用java.util.Optional。在Spring MVC中,@RequestParam@PathVariable@RequestHeader@MatrixVariable支持这个特性。
@RequestMapping(value = {"/simple", "/simple/{game}"}, method = RequestMethod.GET)
public ModelAndView gameHandler(@PathVariable Optional<String> game,
            HttpServletRequest request) {
    if (game.isPresent()) {
        //game.get()
        //corresponds to path "/simple/{game}"
    } else {
        //corresponds to path "/simple"
    }           
}

19

你可以直接这样做:

@RequestMapping(value = "/simple", method = RequestMethod.GET)
public ModelAndView gameHandler(HttpServletRequest request) {
    gameHandler2(null, request)
}

@RequestMapping(value = "/simple/{game}", method = RequestMethod.GET)
public ModelAndView gameHandler2(@PathVariable("game") String game,
        HttpServletRequest request) {

3
@RequestMapping(value = {"/simple", "/simple/{game}"}, method = RequestMethod.GET)
public ModelAndView gameHandler(@PathVariable(value="example",required = false) final String example)

尝试这种方法,这对我很有效。


1

我刚刚进行了测试,但是通过结合上述解决方案,我得到了以下结果:

@RequestMapping(value = {"/simple", "/simple/{game}"}, method = RequestMethod.GET)
public ModelAndView gameHandler(@PathVariable(value = "game", required = false) String example,
                                HttpServletRequest request) {
    if (example != null) {
        //...
    } else {
        //pick first, ...
    }
}

现在当你使用"/simple"时,字符串示例将为null而不是抛出异常。
简短的解决方案,没有花哨的Optional<>或Map<>。

0

我们可以在控制器中编写多个方法,并使用显式映射和路径变量组合,以排除可选变量(如果使用旧版Spring)。

在我的情况下,我想开发一个API,以获取旧设备的回收价值,其中参数可以是品牌,型号和网络,但网络是可选的。

处理此问题的一种选择是将网络用作请求参数,而不是PathVariable。例如/value/LG/g3?network = vodafone,但我不喜欢这种方法。

对我来说,更清洁的方法是使用以下内容 /refurbValue/LG/g3 /refurbValue/LG/g3/vodafone

   @RequestMapping(value = "/refurbValue/{make}/{model}/{network}", method = RequestMethod.GET)
@ResponseStatus(HttpStatus.OK)
@ResponseBody
def getRefurbValueByMakeAndModelAndNetwork(@PathVariable String make, @PathVariable String model, @PathVariable String network ) throws Exception {
    //logic here
}

@RequestMapping(value = "/refurbValue/{make}/{model}", method = RequestMethod.GET)
@ResponseStatus(HttpStatus.OK)
@ResponseBody
def getRefurbValueByMakeAndModel(@PathVariable String make, @PathVariable String model) throws Exception {
    //logic here
}

在上面的例子中,两个控制器都可以使用相同的服务方法,并且可以处理参数。在我的情况下,我正在使用Groovy,因此可以轻松地使用可选参数,例如
Map getRefurbValue(String brand, String model, String network="")

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