Spring MVC:如何指示路径变量是否为必需?

42

我正在开发一个Spring Web项目。在控制器方法中,我可以使用RequestParam来指示参数是否是必需的。例如:

@RequestMapping({"customer"}) 
public String surveys(HttpServletRequest request, 
@RequestParam(value="id", required = false) Long id,            
Map<String, Object> map)

我想使用如下所示的PathVariable:

@RequestMapping({"customer/{id}"}) 
public String surveys(HttpServletRequest request, 
@PathVariable("id") Long id,            
Map<String, Object> map) 

我该如何指示路径变量是否必需?我需要将其设置为可选,因为在创建新对象时,直到保存后才会有关联的ID可用。

谢谢帮助!


2
我认为你正在询问与此问题相同的事情:https://dev59.com/kW445IYBdhLWcg3wWZAU - TravJenkins
1
可能是Spring 3.0中,我可以创建一个可选的路径变量吗?的重复问题。 - Oleg Estekhin
7个回答

63

VTTom 的解决方案正确,只需将 "value" 变量更改为数组,并列出所有 URL 可能性:value={"/", "/{id}"}

@RequestMapping(method=GET, value={"/", "/{id}"})
public void get(@PathVariable Optional<Integer> id) {
  if (id.isPresent()) {
    id.get()   //returns the id
  }
}

3
请注意,这需要使用Spring 4.1+和Java 1.8版本以上。 - Aniket Thakur
1
当您使用 "/" 时,对于 http://.../foo/bar 地址,您将得到404错误,而对于 http://.../foo/bar/ 的响应。我使用空字符串 "" 作为第一个值。 - csharpfolk
4
请注意,自Spring 4.3.3以来,您还可以使用 @PathVariable(required = false) 并在变量不存在时获得null。 - Nicolai Ehemann
4
@NicolaiEhemann,谢谢您提供正确的信息。但那只是行不通的。可以这样写:@RequestMapping(value = {"foo", "foo/{bar}"})@PathVariable(required = false) - Ram
我的评论只是对答案(应该是被接受的答案)的补充,因为它提供了一种替代方法,而不是将id设为可选项。 - Nicolai Ehemann

42

无法将其设为可选,但您可以创建两种方法,其中一个具有 @RequestMapping({"customer"}) 注释,另一个具有 @RequestMapping({"customer/{id}"}),然后在每个方法中根据需要进行操作。


1
Tristan,我选择了VTTom的帖子作为答案,以使阅读此问题的任何人受益。你是正确的。 - curious1
可以的,可以看看其他答案(@curious1 随意接受其他答案之一)。 - rogerdpack
可以使用以下方式: @PatchMapping(path = {"/{procurementInitId}/updateLinkedPurchase/{purchaseId}", "/{procurementInitId}/updateLinkedPurchase"}, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public HttpEntity<?> updateLinkedPurchase( @PathVariable(name = "procurementInitId") Integer procurementInitId, @PathVariable(name = "purchaseId", required = false) Integer purchaseId) { - Michael Gaev

35

我知道这是一个老问题,但搜索“可选路径变量”会使这个答案排名靠前,所以我认为值得指出的是,自Spring 4.1使用Java 1.8以来,可以使用java.util.Optional类实现此功能。

例如(请注意,value必须列出所有可能需要匹配的路由,即具有id路径变量和没有id路径变量的路由。感谢@martin-cmarko指出这一点)

@RequestMapping(method=GET, value={"/", "/{id}"})
public void get(@PathVariable Optional<Integer> id) {
  if (id.isPresent()) {
    id.get()   //returns the id
  }
}

2
有人能验证这个是否有效吗?如果我在没有id的情况下尝试访问此路径,我会得到404错误(Spring MVC 4.1.4,Java 1.8.0_66)。 - Wonko
是的,这样做不起作用,因为没有ID的路径将无法匹配并命中此控制器。 - Aniket Thakur
1
感谢您提到 Optional 类的 pkg 名称。 - Binita Bharati
1
这部分 value={"/", "/{id}"} 使其适用于带有和不带有 id 的路由。 - sr9yar

3

VTToms的答案不起作用,因为没有id在路径中匹配(即找不到相应的HandlerMapping),因此控制器将不会被调用。相反,您可以这样做-

@RequestMapping({"customer/{id}","customer"}) 
public String surveys(HttpServletRequest request, @PathVariable Map<String, String> pathVariablesMap, Map<String, Object> map) {
    if (pathVariablesMap.containsKey("id")) {
        //corresponds to path "customer/{id}"
    }
    else {
        //corresponds to path "customer"
    }
}

您也可以使用java.util.Optional,其他人已经提到过了,但它需要Spring 4.1+和Java 1.8。


1

我知道这是一个老问题,但由于没有答案提供一些更新的信息,而且我正好路过这里,所以我想要做出我的贡献:

自从Spring MVC 4.3.3引入了Web Improvements

@PathVariable(required = false) //true is default value

是合法且可能的。


0

在使用'Optional'(@PathVariable Optional id)或Map (@PathVariable Map pathVariables)时存在问题,因为如果您尝试通过调用控制器方法创建HATEOAS链接,则会失败,因为Spring-hateoas似乎是预先java8的,并且不支持'Optional'。它还无法调用任何带有@PathVariable Map注释的方法。

这里是一个演示Map失败的示例

   @RequestMapping(value={"/subs","/masterclient/{masterclient}/subs"}, method = RequestMethod.GET)
   public List<Jobs>  getJobListTest(
         @PathVariable  Map<String, String> pathVariables,
         @RequestParam(value="count", required = false, defaultValue = defaultCount) int count) 
   {

      if (pathVariables.containsKey("masterclient")) 
      {
         System.out.println("Master Client = " + pathVariables.get("masterclient"));
      } 
      else 
      {
         System.out.println("No Master Client");
      }




  //Add a Link to the self here.
  List list = new ArrayList<Jobs>();
  list.add(linkTo(methodOn(ControllerJobs.class).getJobListTest(pathVariables, count)).withSelfRel());

  return list;

}


0
@RequestMapping(path = {"/customer", "/customer/{id}"})
public String getCustomerById(@PathVariable("id") Optional<Long> id) 
        throws RecordNotFoundException 
{
    if(id.isPresent()) {
        //get specific customer
    } else {
        //get all customer or any thing you want
    }
}

现在所有的URL都已经映射好并且可以正常工作了。
/customer/123
/customer/1000
/customer - 现在可以使用了!!

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