Unable to populate modelAttribute in spring - java

I am unable to get the ModelAttribute for second request.
My first request is initForm() method I prepared Command object and able to display the command in jsp.
Through initForm() I am populating command and that command I want in editForm when I will do ajax call.
Here is my spring form
<form:form method="POST" action="addstudentdetails.htm" commandName="command">
Ignore what is inside this
Name: Shoaib Age:23 edit
</form:form>
My ajax request:
function editStudentDetails(studentId,index){
$.ajax(
{url:"editstudentdetails.htm",
method:"GET",
data:{"action":"edit","id":studentId,"index":index},
success: function(data) {
jQuery("#studentDetailsDiv").html(data)
}
}
)
}
In editStudentDetails() method I have method ajax call to go editForm() of the controller.
Here is my controller:
#Controller
public class StudentDetailsController {
#Autowired
private StudentDetailsDAO studentDetailsDAO;
#RequestMapping(value="/studentdetails.htm",method = RequestMethod.GET)
public String initForm(HttpServletRequest request,ModelMap map){
String action=request.getParameter("action");
StudentDetailsCommand command=new StudentDetailsCommand();
System.out.println("in controller"+action);
command.setStudents(studentDetailsDAO.findAll());
map.addAttribute("command", command);
return "studentdetails";
}
#RequestMapping(value="/editstudentdetails.htm",method = RequestMethod.GET)
public String editForm(ModelMap map,HttpServletRequest request){
map.addObject("index", request.getParameter("index"));
StudentDetailsCommand command=(StudentDetailsCommand)map.get("command");
System.out.println(command);
System.out.println(command.getStudents());//NullPointerException here.
map.addObject("command", command);
return "studentdetails";
}
}
Even tried #ModelAttribute("studentDetailsCommand") but didn't worked.
I am new to Spring 3.0 and I followed all solutions which are given here but nothing worked.Can anyone help me out please?

Model attributes only exist during the life cycle of one HttpServletRequest. Consider reading my answer here.
In your initForm method, you do the following
map.addAttribute("command", command);
this add an attribute named command to the model attributes. This attribute will eventually find its way into the HttpServletRequest attributes and be available to your JSP. In here
<form:form [...] modelAttribute="studentDetailsCommand" commandName="command">
first of all, modelAttribute and commandName have the same purpose, ie. to find an attribute in the model. If you remove commandName you will get an Exception because there is no model attribute named studentDetailsCommand. Here your commandName's value is overwriting your modelAttribute's value.
When the Servlet container is finished rendering your JSP, the rendered content is sent as the body of the HTTP response. At this point, the request has been handled and the HttpServletRequest and the model attributes are garbage collected.
When you send your new request through AJAX, there is no longer any model attribute named studentDetailsCommand (there actually never was).
Consider using Flash Attributes.
Related:
How to read flash attributes after redirection in Spring MVC 3.1?
Spring RedirectAttributes: addAttribute vs addFlashAttribute
Use of getFlashAttributes() in Spring's RedirectAttributes

Related

pass parameter through <a href=""> and get it to spring mvc controller

I am trying to pass clusterId=1 as parameter from
<a href="http://192.168.11.134:8080/UniconnectConfigurationWeb/nodes?clusterId=1"> and get it into spring mvc controller through #PathParam("clusterId")Integer clusterId. But I'm getting 404 error.
Guide me how to pass parameter through anchor tag and how to hit controller and get the parameter value.
I am sharing my code below,
#RequestMapping(value = "/nodes?clusterId={clusterId}", method = RequestMethod.GET)
public ModelAndView nodes(#RequestParam("clusterId")Integer clusterId,HttpSession session, HttpServletRequest request) {
System.out.println(clusterId);
return dashboard;
}
}
<c:url var="myURL" value="http://192.168.11.134:8080/UniconnectConfigurationWeb/nodes">
<c:param name="clusterId" value="1"/>
</c:url>
Here you are using clusterId as Request Parameter , and passing from client side to server side. but in your server side code you are used ?clusterId={clusterId} in Request Mapping annotation and you are trying to receive that request parameter with #RequestParam Annotation. here #RequestParam is enough for receiving Request Parameter. so, no need to use this ?clusterId={clusterId}`, this is not correct way of writing server side URL.
it may helps you for better understanding #RequestParam vs #PathVariable

Preserving model state with Post/Redirect/Get pattern and URL rewriting

First of all, I know that there are similar questions regarding "Preserving model state with Post/Redirect/Get pattern", but none of these have my very specific problem:
background:
My Code is working in an enterprise CMS software which does a lot of things. One of them is URL rewriting: Whenever I generate Links to my controller, dependending on the environment, the links are shortened - That's a SEO thing and can't be discussed.
I.e. if my Controller URL is /webapp/servlet/myController/doSomething, the generated URL will be /myController/doSomething. There's some LinkProcessing functionality that we have to use.
An apache rewrite rule will then expand this short url to /webapp/servlet/myController/doSomething when the apache uses mod_rewrite to call the corresponsing code on the tomcat:
RewriteCond %{REQUEST_URI} ^/myController/(.*)
RewriteRule ^/myController/(.*) /webapp/servlet/myController/$1 [PT,L]
Problem:
I'm trying to implement the Post/Redirect/Get pattern using Spring 3.1.2. I'm generating a form and POST it to the Controller, which validated and makes a redirect to either the success or error page using GET (Post/Redirect/Get pattern).
(highly simplified) Code:
#RequestMapping()
public class MyController {
#RequestMapping(value = "/doDispatch", method = RequestMethod.POST)
public RedirectView handleDispatch(RedirectAttributes redirectAttributes,
#Validated #ModelAttribute FormBean formBean,
BindingResult binding) {
if (binding.hasErrors()) {
redirectAttributes.addFlashAttribute(formBean);
redirectAttributes.addFlashAttribute(BindingResult.MODEL_KEY_PREFIX+"formBean", binding);
return new RedirectView(generateLink("/error"));
} else {
redirectAttributes.addFlashAttribute(formBean);
redirectAttributes.addFlashAttribute(BindingResult.MODEL_KEY_PREFIX+"formBean", binding);
return new RedirectView(generateLink("/success"));
}
}
#RequestMapping(value = "/success")
public ModelAndView handleSuccess(#ModelAttribute FormBean formBean) {
// do stuff (save things in the DB)
// ...
final ModelAndView modelAndView = createModelAndView(formBean);
modelAndView.addObject("success", true);
return modelAndView;
}
#RequestMapping(value = "/error")
public ModelAndView handleError(#Validated #ModelAttribute FormBean formBean,
BindingResult binding) {
final ModelAndView modelAndView = createModelAndView(formBean);
modelAndView.addObject("binding", binding);
modelAndView.addObject("formBean", formBean);
return modelAndView;
}
}
The problem ist that this generateLink() method will either generate links starting with /webapp/servlet or not - depending on the environment/success. And that's how this whole Enterprice CMS thing works. (that's the part which cannot be discussed)
Spring Flash-Attributes on the other hand work hand in hand with the URLs that are returned and store the URL as part of the FlashMap:
Quote from http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-flash-attributes :
To reduce the possibility of such issues, RedirectView automatically "stamps" FlashMap instances with the path and query parameters of the target redirect URL. In turn the default FlashMapManager matches that information to incoming requests when looking up the "input" FlashMap.
Since the next request (let's say I've had an error and returned "/myController/error") will be expanded to /webapp/servlet/myController/error, the FlashMap will not apply to this request, since the URLs do not match.
The code that is responsible is this here (AbstractFlashMapManager.java:157 ff):
protected boolean isFlashMapForRequest(FlashMap flashMap, HttpServletRequest request) {
if (flashMap.getTargetRequestPath() != null) {
String requestUri = this.urlPathHelper.getOriginatingRequestUri(request);
if (!requestUri.equals(flashMap.getTargetRequestPath())
&& !requestUri.equals(flashMap.getTargetRequestPath() + "/")) {
return false;
}
}
// ...
}
Question:
Do you know a way how I can still generate short URLs on the one hand, but pass the FlashAttributes to the following GET request?
Best regards and thanks for your help in advance,
Alexander
The best solution I've found so far is using an Interceptor that updates the targetRequestPath by prefixing /<webappPath>/<servletPath> to those FlashMaps from RequestContextUtils.getOutputFlashMap(request) that are missing this information. BTW: this can only be done in the afterCompletion method, because otherwise the targetRequestPath won't be set at all, when using a RedirectView.
Any other, better solutions?

How to return a variable in every page from my Spring MVC application from the same controller method?

I want to return a model from my Spring MVC controller, which will be visible to all pages in my application.
So, I need a variable which return some user details.
This is my code:
#RequestMapping(value = "/*", method = RequestMethod.GET)
public void status(Model model){
Authentication auth = SecurityContextHolder.getContext()
.getAuthentication();
String username = auth.getName();
Manager mgr = managerService.findOne(username);
model.addAttribute("buget", mgr.getTeam().getTeamBuget());
}
And in my jsp page, i write something like this:
<li> <c:out value="${buget}" /> <span class="glyphicon glyphicon-euro"></span></li>
I want to be able to print the ${buget} in every page from my app.
So, my method don't work, nothing is appear in my pages and the biggest problem
for me is that I don't get any exceptions or errors which could help me. Who can help me with some advices?
I'm not entirely sure what it is that you're trying to do. Do you mean that you want buget to be part of every page that you hit? If so, you have to insert it into the model. Based on your code, I'm assuming that you have the mistaken impression that status is going to be called regardless of whatever page you hit. Spring will resolve to the most-specific handler and so if you have another handler method in another controller that is more specific, Spring will use that. But even if the one you have was called, how would Spring know that it has to call the most-specific one next? So how would you add page-dependent model attributes to the model?
If you want buget to be part of every response, you can use #ControllerAdvice (see here for a blog post with more details):
#ControllerAdvice
public class BugetControllerAdvice {
#ModelAttribute
public void addBugetToModel(Model model) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String username = auth.getName();
Manager mgr = managerService.findOne(username);
model.addAttribute("buget", mgr.getTeam().getTeamBuget());
}
}
Spring will now call this method before every handler-method in every controller. You can also take a look at the Spring Reference for more information.

Passing model attribute during redirect in spring MVC and avoiding the same in URL

My objective is to pass model attributes from controller to JSP page during a redirect and avoid the attribute being displayed in URL. The source code below is validating login from datastore using java data objects.
Controller:
#Controller
public class LoginController {
int count;
PersistenceManager pm = PMF.get().getPersistenceManager();
//Instance of data class
User user;
ModelAndView modelAndView=new ModelAndView();
#RequestMapping(value="/Login",method = RequestMethod.POST)
public ModelAndView loginValidate(HttpServletRequest req){
//Getting login values
String uname=req.getParameter("nameLogin");
String pswd1=req.getParameter("pswdLogin");
count=0;
user=new User();
//Generating Query
Query q = pm.newQuery(User.class);
q.setFilter("userName == userNameParam");
q.declareParameters("String userNameParam");
try{
List<User> results = (List<User>) q.execute(uname);
for (User u: results) {
String userName=u.getUserName();
if(userName.equals(uname)){
System.out.println(u.getPassword());
if(u.getPassword().equals(pswd1)){
count=count+1;
modelAndView.setViewName("redirect:welcome");
modelAndView.addObject("USERNAME",uname);
return modelAndView;
}
//rest of the logic
}
JSP:
<h1>Welcome ${USERNAME} </h1>
My current URL is /welcome?USERNAME=robin
My goal is to display it as /welcome
Also, my page is supposed to display "Welcome robin" whereas it displays only Welcome.
RedirectAttributes only work with RedirectView, please follow the same
#RequestMapping(value="/Login",method = RequestMethod.POST)
public RedirectView loginValidate(HttpServletRequest req, RedirectAttributes redir){
...
redirectView= new RedirectView("/foo",true);
redir.addFlashAttribute("USERNAME",uname);
return redirectView;
}
Those flash attributes are passed via the session (and are destroyed immediately after being used - see Spring Reference Manual for details). This has two interests :
they are not visible in URL
you are not restricted to String, but may pass arbitrary objects.
You need to be careful here because I think what are you trying to do is not supported for a good reason. The "redirect" directive will issue a GET request to your controller. The GET request should only retrieve existing state using request parameters, this is the method contract. That GET request should not rely on a previous interaction or on any object stored some where in the session as a result of it. GET request is designed to retrieve existing (persisted) state. Your original (POST) request should have persisted everything you need for you GET request to retrieve a state.
RedirectAttributes are not designed to support you in this case, and even if you managed to correctly use it it will only work once and then they will be destroyed. If you then refresh the browser you will get an application error because it cannot find your attributes anymore.

Spring MVC: Error 400 The request sent by the client was syntactically incorrect

This seems to be a common issue. I have gone all the answers given in SO but could not make it work.I am trying to integrate Spring MVC+Freemarker in already existing web application. It works fine for the GET request and Freemarker Template reads java object provided by Controller without any issue.
But Form submission is not able to hit Controller method. Finally I made log4j work. Here is the error I am getting:
Error
HandlerMethod details:
Controller [application.entry.controller.UserController]
Method [public void application.entry.controller.UserController.handleSave(java.lang.String)]
org.springframework.web.bind.MissingServletRequestParameterException:
Required String parameter 'action' is not present
Freemarker:
<form method="POST" action="save.html">
------------
<input type="submit" class="btnnew" name="saveWithoutValidation" value="Save Without Validation"></input>
<input type="submit" class="btnnew" name="submit" value="Submit"></input>
</form>
context-root is PORTAL.
spring-servlet.xml
<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="cache" value="true"/>
<property name="prefix" value=""/>
<property name="suffix" value=".ftl"/>
web.xml
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Controller
#RequestMapping(value="/save", method=RequestMethod.POST)
public void handleSave(#RequestParam String action){
if( action.equals("submit") ){
System.out.println("Damn! You clicked submit");
}
else if( action.equals("saveWithoutValidation") ){
System.out.println("Sweet! You want no string attached.");
}
}
For logs I have tried to add log4j.logger.org.springframework.web=DEBUG to my existing log4j.properties but it didn't work.
I also had this issue and my solution was different, so adding here for any who have similar problem.
My controller had:
#RequestMapping(value = "/setPassword", method = RequestMethod.POST)
public String setPassword(Model model, #RequestParameter SetPassword setPassword) {
...
}
The issue was that this should be #ModelAttribute for the object, not #RequestParameter. The error message for this is the same as you describe in your question.
#RequestMapping(value = "/setPassword", method = RequestMethod.POST)
public String setPassword(Model model, #ModelAttribute SetPassword setPassword) {
...
}
The #RequestParam String action suggests there is a parameter present within the request with the name action which is absent in your form. You must either:
Submit a parameter named value e.g. <input name="action" />
Set the required parameter to false within the #RequestParam e.g. #RequestParam(required=false)
Another possible cause is to have the wrong order of RequestMapping attributes.
As spring doc says:
An #RequestMapping handler method can have a very flexible signatures.
The supported method arguments and return values are described in the
following section. Most arguments can be used in arbitrary order with
the only exception of BindingResult arguments. This is described in
the next section.
If you scroll down the doc, you will see that the BindingResult has to be immediatelly after the model attribute, since we can have multiple model objects per request and thus multiple bindings
The Errors or BindingResult parameters have to follow the model object
that is being bound immediately as the method signature might have
more than one model object and Spring will create a separate
BindingResult instance for each of them so the following sample won’t
work:
Here are two examples:
Invalid ordering of BindingResult and #ModelAttribute.
#RequestMapping(method = RequestMethod.POST) public String
processSubmit(#ModelAttribute("pet") Pet pet, Model model,
BindingResult result) { ... } Note, that there is a Model parameter in
between Pet and BindingResult. To get this working you have to reorder
the parameters as follows:
#RequestMapping(method = RequestMethod.POST) public String
processSubmit(#ModelAttribute("pet") Pet pet, BindingResult result,
Model model) { ... }
I was facing a similar issue and found that a few fields like Date were not getting a concrete value, once given the values things worked fine. Please make sure you do not have date or any other field present on the form which needs a concrete value.
Based on the error:
Required String parameter 'action' is not present
There needs to be a request parameter named action present in the request for Spring to map the request to your handler handleSave.
The HTML that you pasted shows no such parameter.
Controller trying to find the "action" value in bean but according to your example you have not set any bean name of "action".
try to do name="action".
#RequestParam always find in the bean class.
My problem was the lack of BindingResult parameter after my model attribute.
#RequestMapping(method = RequestMethod.POST, value = "/sign-up", consumes = "application/x-www-form-urlencoded")
public ModelAndView registerUser(#Valid #ModelAttribute UserRegistrationInfo userRegistrationInfo
HttpServletRequest httpRequest,
HttpSession httpSession) { ... }
After I added BindingResult my controller became
#RequestMapping(method = RequestMethod.POST, value = "/sign-up", consumes = "application/x-www-form-urlencoded")
public ModelAndView registerUser(#Valid #ModelAttribute UserRegistrationInfo userRegistrationInfo, BindingResult bindingResult,
HttpServletRequest httpRequest,
HttpSession httpSession) { ..}
Check answer #sashok_bg
#sashko_bg Mersi mnogo
Your request mapping is /save, but your POST is to /save.html. Changing the POST to /save should fix it.
#CookieValue(value="abc",required=true) String m
when I changed required from true to false,it worked out.
Please keep your
<form method="POST" action="XYZ">
#RequestMapping(value="/XYZ", method=RequestMethod.POST)
public void handleSave(#RequestParam String action){
Your form action attribute value must match to value of #RequestMapping, So that Spring MVC can resolve it.
Also, as you told it is giving 404 after changing, for this, can you please check whether control is entering inside handleSave() method.
I think, as you are not returning any thing from handleSave() method, you have to look at it.
if it still not work, can you please post your spring logs.
Also, make sure that your request should come like
/PORTAL/save
if there is anything between like PORTAL/jsp/save the mention in #RequestMapping(value="/jsp/save")
Add BindingResult parameter in your method. For reference please my code below.
save(#ModelAttribute Employee employee,BindingResult bindingResult)

Categories

Resources