I have a controller that gets an ID from a form in search.jsp. I want it to redirect to entitydemo.jsp, which should be able to access EntityDemo and output its attributes. How do I do that? Do I need to use redirect and put EntityDemo as a session attribute somehow?
#Controller
public class SearchEntityController {
#RequestMapping(value = "/search", method = RequestMethod.GET)
public EntityDemo getEntityDemoByID(#ModelAttribute("search") Search search, BindingResult result) {
EntityDemo entityDemo = null;
if (search.getId() != null) {
int id = Integer.parseInt(search.getId());
entityDemo = DBHelper.getEntityDemo(id);
}
return entityDemo;
}
}
Assuming that you have some class named EntityDemo which has Getters and Setters for all the fields, I think you should do something like so:
#Controller
public class SearchEntityController {
#RequestMapping(value = "/search", method = RequestMethod.GET)
public ModelAndView getEntityDemoByID(#ModelAttribute("search") Search search, BindingResult result) {
EntityDemo entityDemo = null;
Map<String, Object> model = new HashMap<String, Object>();
if (search.getId() != null) {
int id = Integer.parseInt(search.getId());
entityDemo = DBHelper.getEntityDemo(id);
model.put("entityDemo", entityDemo);
}
return new ModelAndView(new RedirectView(pageIWantToRedirectTo), model);
}
}
Then, in your JSP, you can use JSTL and do something like this: ${entityDemo.name}, where name is a field I am assuming that the EntityDemo class has together with an appropriate Getter, this being public String getName(){return this.name;}.
To my knowledge, Controller methods do not return entire objects, they either return String values which denote the name of the view, such as \foo\bar\myPage.jsp or else, entire ModelAndView objects (there are 2 types of objects, one of them has portlet in its full name and the other has servlet. In this case you must use the one that has servlet in its full name. Just for clarity, when I say full name, I mean the name which includes the package within which it resides. If memory serves me well the one you are looking for is in springframework...servlet.ModelAndView or something like that.
EDIT: If you want to redirect upon submit, then, you will need to make 2 controllers, one which will render the form and the other which will redirect once the form is submitted.
Regarding your JSP Page, you should have an xml file name dispatcher-servlet.xml. The name could be different, depending on your configurations in web.xml, but they all have the structure of <servletname>-servlet.xml. There should be a property named viewResolver (Although this should be the case, certain IDE's do not populate much for you. On the other hand, IDE's such as Netbeans set up most of the initial configuration for you). This is another controller which acts upon your views. What it does is that it automatically appends items before and after your view name which you specify in your controller. Usually it appends a prefix of pages/jsp/ and a suffix of .jsp. So, if you have a page with the following path pages/jsp/myPage.jsp, all you need to pass in your controller would be myPage. The full path to the page will be constructed by the view resolver. If you pass in the whole URL, it will still keep on adding stuff so the page still won't be found even though you specified a correct path.
I got it to work using 2 methods in my controller - one to display the form and another for the search results
Controller:
#Controller
public class SearchEntityController {
#RequestMapping(value = "/search", method = RequestMethod.GET)
public void searchForm(Model model) {
model.addAttribute(new Search());
}
#RequestMapping(value = "/entitydemo", method = RequestMethod.POST)
public void showSearchResult(#ModelAttribute Search search, Model model) {
model.addAttribute("entityDemo", getEntityDemo(search));
}
// code to load entity here
}
(Search is a class with an int id and accessors)
Form in search.jsp:
<form:form action="entitydemo" commandName="search">
ID: <form:input path="id" />
</form:form>
Showing results in entitydemo.jsp:
<core:out value="${entityDemo.foo}" /> <br/>
<core:out value="${entityDemo.bar}" />
Related
I am referring the example from here
where the #ModelAttribute is placed at the method level
/**
* Retrieves all addresses and allows them to be used as a model
* #return a model attribute containing addresses
*/
#ModelAttribute("addresses")
public List<Address> getAllAddresses() {
// Delegate to service
return addressService.getAll();
}
#InitBinder
public void initBinder(WebDataBinder webDataBinder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-mm-dd");
dateFormat.setLenient(false);
webDataBinder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}
/**
* Handles and retrieves a JSP page containing all addresses.
* We use the #ModelAttribute to pass the data to the view
*
* #return the name of the JSP page
*/
#RequestMapping(value="list1", method = RequestMethod.GET)
public String getAllUsingModelAttribute() {
logger.debug("Received request to show all addresses page");
// No need to add the model here
// It has been automatically added when we used the #ModelAttribute annotation earlier
// The name of the ModelAttribute is "addresses". Your JSP should reference "addresses"
// This will resolve to /WEB-INF/jsp/addressespage.jsp
return "addressespage";
}
My question is, is the method annotated with #ModelAttribute autofired when the request comes to the controller? In this case method getAllAddresses(). As in the example I don't see this method called explicitly anywhere.
Or it is fired when the request comes to the method immediately placed after it containing #RequestMapping?
Same question for #initBinder is the method annotated with it autofired after form submission?
When a page is going to render if the page has a form which has been made by form taglib using Spring like:
<form:form commandName="addresses" method="post">
this lead your page to look for a proper #ModelAndAttribute with name 'addresses'. If your program was able to find that (like the one you have defined)
#ModelAttribute("addresses")
public List<Address> getAllAddresses() {
// Delegate to service
return addressService.getAll();
}
that make a model available for your form with a List ready to change !
then you can use another method for submitting the form like this:
#RequestMapping(value="path", method=RequestMethod.POST)
public String doSomethingForMe(#Valid #ModelAttribute("addresses") List <Address>, BindingResult result) {
if(result.hasErrors()){
return "TO_THE_PAGE_YOU_WANT_FOR_SHOWING_THE_ERROR_TO_USER";
}
// do the other stuffs you want !
}
I just write this code here, so sorry if you found out any typo problem but that's the story !
Good Luck !
Try to debug your controller and put some logging statements.
The first things you culd see is the call to #ModelAttribute annotated method.
Your initBinder will be called if you put a custom object into Model or if your handler method declare a custom Object as parameter.
#ModelAttribute("obj")
public List<Address> getAllAddresses() {
// Delegate to service
return new CustomObject();
}
#RequestMapping(value="list1", method = RequestMethod.GET)
public String getAllUsingModelAttribute(CustomObject customObject) {
I am new to spring MVC. i want to attach a model bean to a form which binds values and pass it to controller. so i did the following way
in jsp
<form:form modelattribute="model">
<form:input path="var1"/>
</form:form>
in controller
pulic void method(#modelattribute("model")Bean bean)
{
//my code
}
but when am accessing the form it throwing error as exception while rendering jsp, no such bean exists with name model
how to solve this? help me
Suppose your model class looks like:
public class MyModel{
private String propOne;
private String porpTwo;
/*Skipping getters and setters*/
}
Use #ModelAttribute to map the user inputs to your form bean:
#RequestParam("/myPage")
public String myController(#ModelAttribute MyModel myModel){
/*Do your processing here*/
}
On jsp page, just give your input fields same name (Html attribute: name) as the properties inside the bean to be mapped:
<form:input name="propOne" class="xyz" />
<form:input name="propTwo" class="xyz" />
Doing this much completes your bean mapping.
You need to save model before render the page.
uiModel.addAttribute("model", new Bean());
In Spring MVC you will be better off using the #ModelAttribute annotation on a method in your controller which supplies your model. This will be called and automatically added to the model before your JSP is rendered.
Something like this
#ModelAttribute
public Model model(){
return new Model();
}
I suggest you have a good read of the Spring MVC documentation
you have to add the form instance to your model during the GET request
#RequestMapping(value = "/foo", method = RequestMethod.GET)
public String handler(final Model uiModel)
uiModel.addAttribute("model", new Bean());
//do something and return a view path, probably
}
and in the handler method to process POST request
#RequestMapping(value = "/foo", method = RequestMethod.POST)
public String handler(final Bean form)
// process your form bean here and return a view path, probably
}
Documentation is available here: http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/mvc.html
Please have a look on Vaibhav method, I have edited it and now its working fine
So I am using Spring MVC 3 with annotations.
I have a simple html form (ExtJS actually) that has three fields.
1) Username
2) Password
3) Color
OK, so username and password belong to a databean called User. color belongs to another bean called Color.
In my UserController, I have:
#RequestMapping(value = "/users/login", method = RequestMethod.POST)
#ResponseBody
public String handleLogin( #ModelAttribute("user") User paUser,
#ModelAttribute("color") Color paColor,
ModelMap map) {
// at this point "paUser" contains both username AND password submitted from form
// however, there is nothing in "paColor"
...
return "user.jsp"
}
What am I doing wrong?
I'm new to Spring, btw.
Thanks
Usually you would create a new class that represents the form (this is known as a form-backing object), such as UserColorForm, that contains properties for each of the inputs in the request body.
Your controller method would then look like:
#RequestMapping(value = "/users/login", method = RequestMethod.POST)
#ResponseBody
public String handleLogin(UserColorForm form, ModelMap map) {
// now you can work with form.getUsername(), form.getColor() etc.
If the FBO bean has property names that match the form input names, Spring will bind the input in the request directly to the properties. i.e. if the form input is username=matt&color=blue then Spring will create a new instance of my form and call setUsername("matt") and setColor("blue").
By the way, you probably don't want the method to be annotated with #ResponseBody if you are going to return the name of the view from the method (user.jsp). #ResponseBody means that the return value of the method should be written directly to the response stream.
I have a session attribute : user, and I have a url that I want to be viewed by both logged in users and publically by people not logged in as a user.
So what I want to do is this :
#Controller("myController")
#SessionAttributes({"user"})
public class MyController {
#RequestMapping(value = "/MyPage/{id}", method = RequestMethod.GET)
public ModelAndView getPage(#PathVariable Integer id) {
return modelandview1;
}
#RequestMapping(value = "/MyPage/{id}", method = RequestMethod.GET)
public ModelAndView getPage(#PathVariable Integer id, #ModelAttribute User user){
return modelandview2;
}
However, I have a feeling its not going to work ... suggestions very welcome.
You only need the second method, the one that takes the User agument as well. When it's called without request attributes available to populate the User model, you'll just get a User instance with all null (or all default) field values, then in the body of the method you treat each situation accordingly
I don't think it's a right case for #SessionAttributes. This annotation is usually used to keep original instance of a form-backing object, to avoid passing irrelevant parts of its state via hidden form fields.
Your sceanrio is completely different, thus it would be better to use HttpSession explicitly:
#RequestMapping(value = "/MyPage/{id}", method = RequestMethod.GET)
public ModelAndView getPage(#PathVariable Integer id, HttpSession session) {
User user = (User) session.getAttribute(...);
if (user != null) {
...
} else {
...
}
}
Also note that #ModelAttribute is a subject to data binding - user can change its fields by passing request parameters. You definitely don't want it in this case.
The question sounds weird, I'm playing around with Spring MVC and am trying to move between two pages and basically I'm creating a JSP page using Spring Form JSTL's so it just uses a POST, and I use a controller to move from one page to the next. But Models are lost from page to page, and I'd like to hide the actual variable so QueryStrings are out of the question(as
far as I know). I know I can use a InternalResourceView, but only allows me to use a model.
I want to transfer a variable that will be exclusive to that page, what's the best way without a model or using QueryStrings?
I was planning on using SessionAttribute to easily define them, but was wondering, how do you remove a SessionAttribute created variable? I tried HttpSession.removeAttribute and it didn't seem to work.
You can also use SessionStatus.setComplete() like this:
#RequestMapping(method = RequestMethod.GET, value="/clear")
public ModelAndView clear(SessionStatus status, ModelMap model, HttpServletRequest request) {
model.clear();
status.setComplete();
return new ModelAndView("somePage");
}
or DefaultSessionAttributeStore.cleanUpAttribute like this:
#RequestMapping(method = RequestMethod.GET, value="/clear")
public ModelAndView clear(DefaultSessionAttributeStore status, WebRequest request, ModelMap model) {
model.remove("mySessionVar");
status.cleanupAttribute(request, "mySessionVar");
return new ModelAndView("somePage");
}
I use it like this on one of my forms that has mulitple sessionAttributes and I want to remove only one of them.
Yes... HttpSession.removeAttribute
You can use the removeAttribute method from the HttpSession class.
you can use WebRequest.removeAttribute(String name, int scope) that works with Spring #SessionAttributes. Quote from #SessionAttributes javadoc - "Alternatively, consider using the attribute management capabilities of the generic {#link org.springframework.web.context.request.WebRequest} interface."
Also look at my example.
#Controller
#SessionAttributes({"sessionAttr"})
public class MyController {
#ModelAttribute("sessionAttr")
public Object defaultSessionAttr() {
return new Object();
}
#RequestMapping(value = "...", method = RequestMethod.GET)
public String removeSessionAttr(WebRequest request, Model model) {
request.removeAttribute("sessionAttr", WebRequest.SCOPE_SESSION);
model.addAttribute("sessionAttr", defaultSessionAttr());
return "myView";
}
}