使用Spring可以使路径变量可选吗?


186

在Spring 3.0中,我可以有一个可选的path变量吗?

例如

@RequestMapping(value = "/json/{type}", method = RequestMethod.GET)
public @ResponseBody TestBean testAjax(
        HttpServletRequest req,
        @PathVariable String type,
        @RequestParam("track") String track) {
    return new TestBean();
}

在这里我想/json/abc/json调用相同的方法。
一种明显的解决方法是声明type为请求参数:

@RequestMapping(value = "/json", method = RequestMethod.GET)
public @ResponseBody TestBean testAjax(
        HttpServletRequest req,
        @RequestParam(value = "type", required = false) String type,
        @RequestParam("track") String track) {
    return new TestBean();
}

然后/json?type=abc&track=aa/json?track=rr将工作

Answers:


194

您不能具有可选的路径变量,但是可以有两个调用相同服务代码的控制器方法:

@RequestMapping(value = "/json/{type}", method = RequestMethod.GET)
public @ResponseBody TestBean typedTestBean(
        HttpServletRequest req,
        @PathVariable String type,
        @RequestParam("track") String track) {
    return getTestBean(type);
}

@RequestMapping(value = "/json", method = RequestMethod.GET)
public @ResponseBody TestBean testBean(
        HttpServletRequest req,
        @RequestParam("track") String track) {
    return getTestBean();
}

5
@Shamik:我认为这是一个使用路径变量的令人信服的理由。组合扩散很快就会失控。
skaffman'2

9
实际上不是因为在填充可选组件时路径不会那么复杂。如果您有两个以上的可选路径元素,则应认真考虑切换其中一些以请求参数。
Patrick Cornelissen

1
并且对某些人来说,具有第二控制器方法调用中的第一控制器方法可以工作以及,如果例如不同参数可以通过一些其它手段来提供
chrismarx

3
请考虑更新,而不是在春天的新版本创建两个控制器的方法,我们可以只使用你的答案,@RequestMapping有两个值,如:stackoverflow.com/questions/17821731/...
csharpfolk

您希望如何维护这些端点?如果不是只有一个路径变量,而是5,那么对我而言,您会做几个端点吗?请帮帮我,替换@PathVariable@RequestParam
Guilherme Alencar,

113

如果您在使用Spring 4.1和Java 8,你可以使用java.util.Optional它支持@RequestParam@PathVariable@RequestHeader@MatrixVariableSpring MVC中-

@RequestMapping(value = {"/json/{type}", "/json" }, method = RequestMethod.GET)
public @ResponseBody TestBean typedTestBean(
    @PathVariable Optional<String> type,
    @RequestParam("track") String track) {      
    if (type.isPresent()) {
        //type.get() will return type value
        //corresponds to path "/json/{type}"
    } else {
        //corresponds to path "/json"
    }       
}

你确定这行得通吗?你自己的答案在这里建议,如果{}类型从路径缺席控制器将不会被击中。我认为PathVariable Map是一种更好的方法,或者使用单独的控制器。
Anshul Tiwari

4
是的,如果您只有"/json/{type}"而类型不存在,它将不会被击中(正如我的链接答案所建议的那样),但是这里有value = {"/json/{type}", "/json" }。因此,如果有任何匹配的控制器方法将被选中。
Aniket Thakur

是否可能相同的值等类型也将是RequestParam和RequestParam?
zygimantus

它可以工作,但是无论如何都不会调用控制器的功能,因为它在那里需要一个参数
EliuX

15
这是可行的,并且从Spring 4.3.3开始,@PathVariable(required = false)如果变量不存在,您也可以使用null并获取null。
Nicolai Ehemann

76

还不知道您是否还可以使用@PathVariable批注注入路径变量的Map。我不确定此功能是否在Spring 3.0中可用或是否在以后添加,但是这是解决示例的另一种方法:

@RequestMapping(value={ "/json/{type}", "/json" }, method=RequestMethod.GET)
public @ResponseBody TestBean typedTestBean(
    @PathVariable Map<String, String> pathVariables,
    @RequestParam("track") String track) {

    if (pathVariables.containsKey("type")) {
        return new TestBean(pathVariables.get("type"));
    } else {
        return new TestBean();
    }
}

1
我一直使用它。当我想要一个方法来处理不同的uri类型时,例如:{“ / json / {type}”,“ / json / {type} / {xyz}”,“ / json / {type} / {abc}“,” / json / {type} / {abc} / {something}“,” / json“}
Vaibs

25

您可以使用:

@RequestParam(value="somvalue",required=false)

用于可选参数而不是pathVariable


1
看来,这是特定于版本的。没有去春3
斯图汤普森

5
当前在spring 3.1项目中使用此方法,并且文档说该方法适用于2.5+版本,因此绝对适用于Spring3。编辑:source
Evan B.

22
是的,但这不是问题所在。问题中确实提到了使用请求参数作为“一个明显的解决方法”,但是问题本身与路径参数有关。这不是可选路径参数的解决方案。
Arjan

9
PathVariable和RequestParam是不同的。
永恒的

9

Spring 5 / Spring Boot 2示例:

阻塞

@GetMapping({"/dto-blocking/{type}", "/dto-blocking"})
public ResponseEntity<Dto> getDtoBlocking(
        @PathVariable(name = "type", required = false) String type) {
    if (StringUtils.isEmpty(type)) {
        type = "default";
    }
    return ResponseEntity.ok().body(dtoBlockingRepo.findByType(type));
}

反应性

@GetMapping({"/dto-reactive/{type}", "/dto-reactive"})
public Mono<ResponseEntity<Dto>> getDtoReactive(
        @PathVariable(name = "type", required = false) String type) {
    if (StringUtils.isEmpty(type)) {
        type = "default";
    }
    return dtoReactiveRepo.findByType(type).map(dto -> ResponseEntity.ok().body(dto));
}

5

Nicolai Ehmann的注释和wildloop的答案的简化示例(适用于Spring 4.3.3+),基本上,您required = false现在可以使用:

  @RequestMapping(value = {"/json/{type}", "/json" }, method = RequestMethod.GET)
  public @ResponseBody TestBean testAjax(@PathVariable(required = false) String type) {
    if (type != null) {
      // ...
    }
    return new TestBean();
  }


-5
$.ajax({
            type : 'GET',
            url : '${pageContext.request.contextPath}/order/lastOrder',
            data : {partyId : partyId, orderId :orderId},
            success : function(data, textStatus, jqXHR) });

@RequestMapping(value = "/lastOrder", method=RequestMethod.GET)
public @ResponseBody OrderBean lastOrderDetail(@RequestParam(value="partyId") Long partyId,@RequestParam(value="orderId",required=false) Long orderId,Model m ) {}

3
您可能需要在答案中添加一些文本,解释为什么您认为这有助于解决当前问题(4年后)。
Qirel 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.