I am beginning with Spring Portlet MVC but I believe this question also applies to Spring MVC. Let me show you this example
#Controller
#RequestMapping(value="VIEW")//this maps to Portlet Mode VIEW
public class LoginController {
#RenderMapping("action=showRegisterPage")
//this annotation is almost the same like #RequestMapping
public String showRegisterPage() {
return "registration";
}
#ModelAttribute("loginForm")
public LoginForm getLoginForm() {
return new LoginForm();
}
}
and then controller for registration page
#Controller
#RequestMapping(value="VIEW")
public class RegistrationController {
#ModelAttribute("user")
public User getUser() {
return new User();
}
}
And the problem is, when I call the showRegisterPage method (action) from page I get redirected to registration.jsp but this exceptions occurs
Caused by: java.lang.IllegalStateException: Neither BindingResult nor
plain target object for bean name 'user' available as request attribute
This can be fixed by putting ModelAttribute user to LoginController but code duplication is not really right way, so how can I solve this correctly?I have also tried moving showRegisterPage method to RegistrationController but then the link is not working. Maybe somebody could elaborate how exactly binding of page to some controller works?
P.S. Both index.jsp and registration.jsp contains <form:form> tag and I also omitted boilerplate code from both controllers.
Exception is thrown because when you go to the registration page model doesn't have user attribute. I guess that your register page contains smth like this
<form:form commandName="user" >
That's why when you paste this code to first controller error is gone
#ModelAttribute("user")
public User getUser() {
return new User();
}
this code provide user object to model.
If you not want copy one method two times you can
#RenderMapping("action=showRegisterPage")
//this annotation is almost the same like #RequestMapping
public String showRegisterPage(Model model) {
model.addAttribute("user", new User());
return "registration";
}
In this case model will be contain user object.
Ideally the showregistrationpage method should b part of the registration controller rather than the login controller.
Related
I've got a #ControllerAdvice class what I use to set user profile information all across the application. In this way, I get the user profile in every single JSP. However, I'm trying to access to that object in a #Controller like this with no success:
#ControllerAdvice
public class CommonControllerAdvice {
#ModelAttribute("PROFILE")
public Profile populateUserProfile(HttpSession session){
return (Profile) session.getAttribute("PROFILE");
}
}
#Controller
public class ActivityController {
#GetMapping("/view/activity/{id}")
public ModelAndView getActivity(ModelAndView modelAndView, #PathVariable Integer id) {
Profile profile = (Profile) modelAndView.getModel().get("PROFILE");
... ...
}
}
But I only get a NullPointerException because the profile is null. However, I know that it is not null because I can use it in the related JSP.
I found a solution. Just pass as a parameter the #ModelAttribute defined in the #ControllerAdvice class, instead of trying to obtain it from the ModelAndView.
#Controller
public class ActivityController{
#GetMapping("/view/activity/{id}")
public ModelAndView getActivity (
ModelAndView modelAndView,
#ModelAttribute Profile profile,
#PathVariable Integer id) {
//Profile object is well populated
//However I don't understand why this model is empty
ModelMap model = modelAndView.getModelMap();
...
}
}
It solved my problem, and I am happy with the solution, nevertheless, I expected to be able to access to this information directly in the ModelMap, and it is empty. I would like to know why.
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
I have an AuthenticationController working fine: all of its methods are running and I can see the logged output of methods. After successful Authentication I return a new modal like this:
modelAndView = new ModelAndView("redirect:/home/");
.....
return modelAndView;
I have another controller named HomePageController, but, after returning a model from Authentication, I am not able to get the code execution in any method of HomePageController.
What mappings do I need?
#Controller
#RequestMapping(value = "/home")
#SessionAttributes({"loginModel"})
public class HomePageController extends AbstractController {
Note: All methods in AuthenticationController are working fine..
web.xml file : http://snipt.org/vgEd7
mct-serverlet.xml file: http://snipt.org/vgEf2
replace trailing space
modelAndView = new ModelAndView("redirect:/home");
.....
return modelAndView;
That will look for /home/index.htm or something.
and in your HomepgageController, make sure there is some method, which returns view for /home url.
#Controller
#RequestMapping(value = "/home")
#SessionAttributes({"loginModel"})
public class HomePageController extends AbstractController {
public string handleHomePage(){
return "View Name";
}
}
Try this return statement : return new ModelAndView("redirect:home");
Avoid / in "redirect:/home/" after home action. It will look for index action automatically.
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}" />
Just looking at the petclinic sample application, and trying to learn form handling.
It seems the form maps to an entity 1:1 correct? Is there any other configuration that has to be done, or will spring just know that all the form inputs map to the entity because that is what was added to the model in the GET request?
#Controller
#RequestMapping("/owners/*/pets/{petId}/visits/new")
#SessionAttributes("visit")
public class AddVisitForm {
private final Clinic clinic;
#Autowired
public AddVisitForm(Clinic clinic) {
this.clinic = clinic;
}
#InitBinder
public void setAllowedFields(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("id");
}
#RequestMapping(method = RequestMethod.GET)
public String setupForm(#PathVariable("petId") int petId, Model model) {
Pet pet = this.clinic.loadPet(petId);
Visit visit = new Visit();
pet.addVisit(visit);
model.addAttribute("visit", visit);
return "pets/visitForm";
}
#RequestMapping(method = RequestMethod.POST)
public String processSubmit(#ModelAttribute("visit") Visit visit, BindingResult result, SessionStatus status) {
new VisitValidator().validate(visit, result);
if (result.hasErrors()) {
return "pets/visitForm";
}
else {
this.clinic.storeVisit(visit);
status.setComplete();
return "redirect:/owners/" + visit.getPet().getOwner().getId();
}
}
}
Note the #SessionAttributes annotation on the class:
When the original GET request comes, the newly created Visit is stored in a session.
When the subsequent POST comes, object stored in the session is updated with the input values from the form.
When Visit is finally persisted, status.setComplete() removes the session attribute.
Without #SesssionAttributes, Visit would be recreated using the form input values when POST comes.
On the jsp you have to spring form tags and bind each variable to the modal attribute using the tags and also have to specify the modalattribute name in the form tag. Tag ref