Spring MVC 中的@RequestParam 处理可选参数

Posted

技术标签:

【中文标题】Spring MVC 中的@RequestParam 处理可选参数【英文标题】:@RequestParam in Spring MVC handling optional parameters 【发布时间】:2014-04-17 21:30:57 【问题描述】:

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

1)http://localhost:8080/submit/id/ID123432?logout=true

2)http://localhost:8080/submit/id/ID123432?name=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 会报错“已经有 'Controller' bean 方法 ... 映射”。

【问题讨论】:

阅读这篇文章:codeflex.co/… 【参考方案1】:

您还需要为namepassword 请求参数提供required = false。这是因为,当您只提供 logout 参数时,它实际上期望 namepassword 以及它们仍然是强制性的。

当您只提供 namepassword 时它起作用了,因为 logout 不是强制性参数,这要归功于 required = false 已经为 logout 提供。

【讨论】:

【参考方案2】:

创建 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 ...

【讨论】:

当有人将注销、名称和密码都传递给 URL 时会发生什么?只需阅读文档,它说!myParam style expressions indicate that the * specified parameter is not supposed to be present in the request. 必须尝试。 它会找到最好的匹配,它可能会尝试使用handleLogin,否则它会给出一个异常,指出找不到映射。 请注意:从安全角度来看,注销应该只接受 POST 请求,因此应该有 2 种方法,保持它们的 URL 相同没有任何意义那么。【参考方案3】:

作为Spring 4.1.1 的一部分,您现在可以完全支持Java 8 Optional (original ticket),因此在您的示例中,只要您将required=false 替换为 Optional for,两个请求都将通过您的单个映射端点您的 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 ...

【讨论】:

@VibhavChaddha 你可以使用这样的东西: if (idOfUser.isPresent()) System.out.println("idOfUser: "+ idOfUser.get()); Intellij 警告:'Optional' 用作参数 'requestedTimelineStart' 的类型更少... (Strg+F1) 检查信息:报告 java.util.Optional 的任何使用, java.util.OptionalDouble、java.util.OptionalInt、java.util.OptionalLong 或 com.google.common.base.Optional 作为字段或参数的类型。 Optional 旨在为库方法返回类型提供有限的机制,其中需要一种清晰的方式来表示“无结果”。如果类需要可序列化,那么使用 java.util.Optional 类型的字段也是有问题的,而 java.util.Optional 不是。 我相信这应该是 Java 8 的新正确答案。 @PeMa 这是一个有争议的警告。我个人认为使用Optional 作为参数而不是null 检查要清楚得多。是的,参数可以是null本身,但返回的Optional值也可以是null。尤其是在这种情况下,当 Spring 将其包装在 Optional 中时在内部处理空参数时。【参考方案4】:

如果有人正在寻找使用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,否则会将字段初始化为空。

【讨论】:

以上是关于Spring MVC 中的@RequestParam 处理可选参数的主要内容,如果未能解决你的问题,请参考以下文章

spring3 mvc的service如何在类中的中的怎么样使用

spring mvc中如何过滤form提交数据中的空格?

spring mvc中的mybatis怎么使用

两个 servlet 中的 Spring、MVC 和 REST

Spring MVC 中的验证

Spring mvc 中的 Servlet