Reputation: 3154
Is it possible for a Spring controller to handle both kind of requests?
1) http://localhost:8080/submit/id/ID123432?logout=true
2) http://localhost:8080/submit/id/ID123432?name=sam&password=543432
If I define a single controller of the kind:
@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 {...}
the HTTP request with "logout" is not accepted.
If I define two controllers to handle each request separately, Spring complains with the exception "There is already 'Controller' bean method ... mapped".
Upvotes: 232
Views: 424878
Reputation: 45040
Before Java 8 and Spring 5 (but works with Java 8+ and Spring 5+ too)
You need to give required = false
for name
and password
request parameters as well. That's because, when you provide just the logout
parameter, it actually expects for name
and password
because they are still "implicitly" mandatory.
It worked when you just gave name
and password
because logout
wasn't a mandatory parameter thanks to required = false
already given for logout
.
Update for Java 8 and Spring 5 (and above)
You can now use the Optional class from Java 8 onwards to make the parameters optional.
@RequestMapping (value = "/path", method = RequestMethod.GET)
public String handleRequest(@RequestParam("paramName") Optional<String> variableName) {
String paramValue = variableName.orElse("");
// use the paramValue
}
Upvotes: 290
Reputation: 2671
In case someone is looking for mapping Optional parameters with Pojo
, same can be done like below.
@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();
}
Note: Do not use @AllArgsConstructor
on POJO
else it will initialize the fields as null.
Upvotes: 1
Reputation: 21381
As part of Spring 4.1.1
onwards you now have full support of Java 8 Optional
(original ticket) therefore in your example both requests will go via your single mapping endpoint as long as you replace required=false
with Optional for your 3 params logout, name, password:
@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 {...}
Upvotes: 195
Reputation: 124441
Create 2 methods which handle the cases. You can instruct the @RequestMapping
annotation to take into account certain parameters whilst mapping the request. That way you can nicely split this into 2 methods.
@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 {...}
Upvotes: 43