Spring控制器是否有可能同时处理这两种请求?

1) http://localhost: 8080 /提交/ id / ID123432 ?注销= true

2) http://localhost: 8080 /提交/ id / ID123432 ?名字= sam&password = 543432

如果我定义一个这样的控制器:

 @RequestMapping (value = "/submit/id/{id}", method = RequestMethod.GET,   
 produces="text/xml")
public String showLoginWindow(@PathVariable("id") String id,
                              @RequestParam(value = "logout", required = false) String logout,
                              @RequestParam("name") String username,
                              @RequestParam("password") String password,
                              @ModelAttribute("submitModel") SubmitModel model,
                              BindingResult errors) throws LoginException {...}

不接受带有“注销”的HTTP请求。

如果我定义两个控制器分别处理每个请求,Spring会报错“There is already 'Controller' bean method…”映射”。


在Java 8和Spring 5之前(但也适用于Java 8+和Spring 5+)

您还需要为名称和密码请求参数提供required = false。这是因为,当您只提供登出参数时,它实际上希望提供名称和密码,因为它们仍然是“隐式”强制的。

当您只提供名称和密码时,它可以工作,因为注销不是一个强制参数,因为已经为注销提供了required = false。

针对Java 8和Spring 5(及以上版本)的更新

现在,从Java 8开始,您可以使用Optional类使参数成为可选的。

@RequestMapping (value = "/path", method = RequestMethod.GET)
public String handleRequest(@RequestParam("paramName") Optional<String> variableName) {
    String paramValue = variableName.orElse("");
    // use the paramValue
}

创建2个处理案例的方法。您可以指示@RequestMapping注释在映射请求时考虑某些参数。这样你就可以很好地把它分成两个方法。

@RequestMapping (value="/submit/id/{id}", method=RequestMethod.GET, 
                 produces="text/xml", params={"logout"})
public String handleLogout(@PathVariable("id") String id, 
        @RequestParam("logout") String logout) { ... }

@RequestMapping (value="/submit/id/{id}", method=RequestMethod.GET, 
                 produces="text/xml", params={"name", "password"})
public String handleLogin(@PathVariable("id") String id, @RequestParam("name") 
        String username, @RequestParam("password") String password, 
        @ModelAttribute("submitModel") SubmitModel model, BindingResult errors) 
        throws LoginException {...}

作为Spring 4.1.1之后的一部分,你现在完全支持Java 8 Optional(原始票据),因此在你的例子中,只要你将required=false替换为Optional,你的3个参数注销,名称,密码,两个请求将通过你的单个映射端点:

@RequestMapping (value = "/submit/id/{id}", method = RequestMethod.GET,   
 produces="text/xml")
public String showLoginWindow(@PathVariable("id") String id,
                              @RequestParam(value = "logout") Optional<String> logout,
                              @RequestParam("name") Optional<String> username,
                              @RequestParam("password") Optional<String> password,
                              @ModelAttribute("submitModel") SubmitModel model,
                              BindingResult errors) throws LoginException {...}

如果有人正在寻找映射可选参数与Pojo,同样可以像下面这样做。

@RequestMapping (value = "/submit/id/{id}", method = RequestMethod.GET,   
 produces="text/xml")
public String showLoginWindow(@PathVariable("id") String id,
                              LoginRequest loginRequest,
                              @ModelAttribute("submitModel") SubmitModel model,
                              BindingResult errors) throws LoginException {...}
@Data
@NoArgsConstructor
//@AllArgsConstructor - Don't use this
public class LoginRequest {
    private Optional<String> logout = Optional.empty();
    private Optional<String> username = Optional.empty();
    private Optional<String> password = Optional.empty();
}

注意:不要在POJO上使用@AllArgsConstructor,否则它会将字段初始化为null。