I'm using the following action on a SpringMvc application:
#RequestMapping(value = "/test", method = RequestMethod.GET)
public ModelAndView test(
#ModelAttribute List<Group> groups
) {
//return whatever
}
My Group class has an 'id' and a 'name' property. Default getter/setter.
How should i call this action in order to have this list correctly instanciated?
I tried something like:
/test?groups.id=2&groups.name=stackrocks&groups.id=3&groups.name=stackrules
Didn't work.
Also tried:
/test?groups[].id=2&groups[].name=stackrocks&groups[].id=3&groups[].name=stackrules
No success.
So, how to bind a list when using SpringMvc?
You can't bind parameters of method with the exactly that signature. #ModelAttribute binds attributes to the fields of the corresponding model object, so you can encapsulate your List into object:
public class Groups {
private List<Group> list = new AutoPopulatingList<Group>(Group.class);
...
}
#RequestMapping(value = "/test", method = RequestMethod.GET)
public ModelAndView test(
#ModelAttribute Groups groups
) {
//return whatever
}
and then call it as follows:
/test?list[0].id=2&list[0].name=stackrocks&list[1].id=3&list[1].name=stackrules
Related
I have a RequestMapping that displays a grid, and another one for loading objects in grid.
#RequestMapping(value = "/grid/{objType}", method = RequestMethod.GET)
public String displayGrid(Model model, #PathVariable("objType") String objType) {
// some code here
}
#RequestMapping(value = "/loadGrid", method = RequestMethod.GET)
public #ResponseBody String loadGrid(Model model) {
// returns a JSON
}
When i display the grid the url is like ../grid/User
The problem is that after the grid is created and a request loadGrid is made, the request is mapped to /grid/loadGrid which is resolved by the first method instead of the second one.
Is there any way to make a request for /grid with nothing after it ?
Or any way to resolve this conflict ?
The collision isn't a problem; spring resolves exact matches first. (see the source code of AbstractHandlerMethodMapping)
Your problem is that you've incorrectly defined your mappings. If you define a #RequestMapping at the class level, all the method #RequestMappings will be prefixed with the defined value.
The following maps three endpoints: /grid, /grid/{objType} and /grid/loadGrid. Note that the #RequestMapping for get() defines no value, only its method because it inherits from the class-level annotation.
#Controller
#RequestMapping(value = "/grid")
public class GridController {
#RequestMapping(method = RequestMethod.GET)
public String get(Model model) {
// ...
}
#RequestMapping(value = "/{objType}", method = RequestMethod.GET)
public String displayGrid(Model model, #PathVariable("objType") String objType) {
// ...
}
#ResponseBody
#RequestMapping(value = "/loadGrid", method = RequestMethod.GET)
public String loadGrid(Model model) {
// ...
}
}
I have a method which is taking #modelattribute as the parameter and is returning model and view object as shown below
#RequestMapping(value = "/pathtorequest", method = RequestMethod.POST)
public ModelAndView redirectdemo( HttpServletRequest req,#ModelAttribute(value="demo") Employee e) {
ModelAndView m=new ModelAndView("result");
Map<String,Object> map=m.getModel();
for(String s:map.keySet()){
System.out.println("key::"+s+" value::"+map.get(s));
}
return m;
}
foreach loop is not printing anything whereas an object is added to model with name=demo.
in the view page which is result i am getting the value of modelattribute in requestScope.
Why the object demo is not added to model map? isnt the demo a model object?
Because, although the Employee object is added by the #ModelAttribute annotated parameter, you then create a brand new ModelAndView with the line
ModelAndView m=new ModelAndView("result");
Then you iterate over m which contains only a view name (i.e. "result") but no model.
When you return a modelAndView, Spring will add to it all the other model attributes created by #ModelAttribute annotations.
If you want to manilpulate the model in your method, add it as a parameter:
#RequestMapping(value = "/pathtorequest", method = RequestMethod.POST)
public ModelAndView redirectdemo( HttpServletRequest req,#ModelAttribute(value="demo") Employee e, ModelMap modelMap) {
for(String s : modelMap.keySet()){
System.out.println("key::"+s+" value::"+modelMap.get(s));
}
}
How can I create a rest controller with spring-mvc that takes multiple parameters with the same name? localhost:8080/api?id=12&id=15&id=88
//pseudocode
#RestController
public class MyRest {
#RequestMapping(method = RequestMethod.GET)
public Object test(#RequestParam value="ids" required=false) List<Integer> ids) {
Sysout(ids);
}
}
?id=12&id=15&id=88 should work automatically with #RequestParam(value="id") List<Integer> ids
I'm trying to achieve a loop of the following steps before save is called.
Show list
add to list
It works adding one item. On the second item added spring has lost the reference to the ModelAttribute which contained an item already and tries to reconstruct it from the form data, which it must not because it contains polymorphic types.
How do I preserve the updated model throughout every add?
Sample
#RequestMapping(value = "/foo", method = RequestMethod.GET)
public String show(#ModelAttribute("foos") ArrayList<Foo> foo, Map model) {
model.put("foo", foo);
return "foo.jsp";
}
#RequestMapping(value = "/addFoo", method = RequestMethod.POST)
public String add(#ModelAttribute("foos") ArrayList<Foo> foo,
RedirectAttributes redirectAttributes) {
foo.add(new FooImpl());
redirectAttributes.addFlashAttribute("foos", foo);
return "redirect:foo";
}
How can I do this without using SessionAttributes?
I would like to know how to read a flash attributes after redirection in Spring MVC 3.1.
I have the following code:
#Controller
#RequestMapping("/foo")
public class FooController {
#RequestMapping(value = "/bar", method = RequestMethod.GET)
public ModelAndView handleGet(...) {
// I want to see my flash attributes here!
}
#RequestMapping(value = "/bar", method = RequestMethod.POST)
public ModelAndView handlePost(RedirectAttributes redirectAttrs) {
redirectAttrs.addFlashAttributes("some", "thing");
return new ModelAndView().setViewName("redirect:/foo/bar");
}
}
What I am missing?
Use Model, it should have flash attributes prepopulated:
#RequestMapping(value = "/bar", method = RequestMethod.GET)
public ModelAndView handleGet(Model model) {
String some = (String) model.asMap().get("some");
// do the job
}
or, alternatively, you can use RequestContextUtils#getInputFlashMap:
#RequestMapping(value = "/bar", method = RequestMethod.GET)
public ModelAndView handleGet(HttpServletRequest request) {
Map<String, ?> inputFlashMap = RequestContextUtils.getInputFlashMap(request);
if (inputFlashMap != null) {
String some = (String) inputFlashMap.get("some");
// do the job
}
}
P.S. You can do return return new ModelAndView("redirect:/foo/bar"); in handlePost.
EDIT:
JavaDoc says:
A RedirectAttributes model is empty when the method is called and is
never used unless the method returns a redirect view name or a
RedirectView.
It doesn't mention ModelAndView, so maybe change handlePost to return "redirect:/foo/bar" string or RedirectView:
#RequestMapping(value = "/bar", method = RequestMethod.POST)
public RedirectView handlePost(RedirectAttributes redirectAttrs) {
redirectAttrs.addFlashAttributes("some", "thing");
return new RedirectView("/foo/bar", true);
}
I use RedirectAttributes in my code with RedirectView and model.asMap() method and it works OK.
Try this:
#Controller
public class FooController
{
#RequestMapping(value = "/foo")
public String handleFoo(RedirectAttributes redirectAttrs)
{
redirectAttrs.addFlashAttribute("some", "thing");
return "redirect:/bar";
}
#RequestMapping(value = "/bar")
public void handleBar(#ModelAttribute("some") String some)
{
System.out.println("some=" + some);
}
}
works in Spring MVC 3.2.2
For all those like me who were having problems with seeing the POST url in the browser when a validation would fail.
The POST url is a private url that should not be exposed to users but it was automatically rendered when a validation failed. i.e. if a field was below a minimum length. I was using #Valid. I wanted the original GET url of the form to show at all times even when validation bounced back to the form, so I did the following:
if (validation.hasErrors()) {
redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.story", validation);
redirectAttributes.addFlashAttribute("story", story);
return new ModelAndView("redirect:/january/2015");
where story is the form object representation, redirectAttributes are RedirectAttributes you put in the method signature and validation is the BindingResult. /january/2015 is the mapping to the GET controller where the form lives.
After this implementation, in the mapping for /january/2015, story comes in intact as follows:
Story story= (Story) model.asMap().get("story");
//story from the POST method
I had to augment my GET method and check if this was not null. If not null, then send this to the form else I would send a newly initialized Story type to the form as default behaviour before.
In this manner, I am able to return to the form with the bindingresults intact (errors show on form) but have my GET url in place of the post url.