Spring redirect keeping parameters after POST - spring

I am using spring 3.2.4 and I have a simple controller that takes a parameter, set it, and redirects the page. For some reason, it is keeping the param even after redirecting. i.e. The page starts at "/" and ends with "/?globalMessage=hereforever", I have tried clearing the modelMap, but that didn't work. I may be misunderstanding something along the lines. I am also adding the model to postHandle in HandlerInterceptor.
#RequestMapping(value = "globalMessage", method = RequestMethod.POST)
public String setGlobalMessage(#RequestParam String globalMessage) {
globalProperties.setProperty("globalMessage", globalMessage);
return "redirect:/";
}
Here is the jsp code in the front
<form method="post" action="/globalMessage">
<input name="globalMessage" type="text" name="message"/>
<input id="submitbutton" type="submit"/>
</form>

Spring's redirect view will automatically expose model attributes as URL parameters: https://jira.springsource.org/browse/SPR-1294. If the globalMessage is set in the model somewhere, then this will get appended to the redirect URL.
You can tell Spring not to do this using the setExposeModelAttributes method.
#RequestMapping(value = "globalMessage", method = RequestMethod.POST)
public String setGlobalMessage(#RequestParam String globalMessage) {
globalProperties.setProperty("globalMessage", globalMessage);
RedirectView redirect = new RedirectView("/");
redirect.setExposeModelAttributes(false);
return redirect;
}

Related

Avoid Spring MVC form resubmission when refreshing the page

I am using spring MVC to save the data into database. Problem is it's resubmitting the JSP page when I am refreshing the page.
Below is my code snippet
<c:url var="addNumbers" value="/addNumbers" ></c:url>
<form:form action="${addNumbers}" commandName="AddNumber" id="form1">
</<form:form>
#RequestMapping(value = "/addNumbers", method = RequestMethod.POST)
public String addCategory(#ModelAttribute("addnum") AddNumber num){
this.numSrevice.AddNumbers(num);
return "number";
}
You have to implement Post/Redirect/Get.
Once the POST method is completed instead of returning a view name send a redirect request using "redirect:<pageurl>".
#RequestMapping(value = "/addNumbers", method = RequestMethod.POST)
public String addCategory(#ModelAttribute("addnum") AddNumber num){
this.numSrevice.AddNumbers(num);
return "redirect:/number";
}
And and have a method with method = RequestMethod.GET there return the view name.
#RequestMapping(value = "/number", method = RequestMethod.GET)
public String category(){
return "number";
}
So the post method will give a redirect response to the browser then the browser will fetch the redirect url using get method since resubmission is avoided
Note: I'm assuming that you don't have any #RequestMapping at controller level. If so append that mapping before /numbers in redirect:/numbers
You can return a RedirectView from the handler method, initialized with the URL:
#RequestMapping(value = "/addNumbers", method = RequestMethod.POST)
public View addCategory(#ModelAttribute("addnum") AddNumber num,
HttpServletRequest request){
this.numSrevice.AddNumbers(num);
String contextPath = request.getContextPath();
return new RedirectView(contextPath + "/number");
}
My answer shows how to do this, including validation error messages.
Another option is to use Spring Web Flow, which can do this automatically for you.

Spring. Bind post method request to base url without trailing slashes

I have problem which solution might be obvious.
I want to bind both post and get method to application base url. I am using annotated controller witch one of the method looks like :
#RequestMapping(value = { "/*" }, method = { RequestMethod.GET, RequestMethod.POST })
public void init(HttpServletRequest request) {
logger.info("Method: " + request.getMethod());
}
And in both cases when i send get or post request i always get result "Method: GET". How can i solve this problem?
It is seems that somewhere in app there is redirection but a can not find any.
Thanks in advance!
The problem is with how you test your program, you are only using GET method by entering url in your browser window in order to test POST
you can create simple html page with content like
<form action="http://localhost:8080/yourapp/yourEntryPoint" method="post">
<input type="text" name="data" value="mydata" />
<input type="submit" />
</form>
and open it in the browser
or use plugin to the browser of your choice (google) "REST services test"
more about Spring MVC
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/htmlsingle/#mvc-ann-requestmapping
In order to map it to the base url for that controller you do not need to put value= on a method
#Controller
#RequestMapping("/yourEntryPoint")
public class YourClass {
#RequestMapping(method = {RequestMethod.GET, RequestMethod.POST })
public void get() {
logger.info("Method: " + request.getMethod());
}
#RequestMapping(value="/new", method = RequestMethod.GET)
public void getNewForm() {
logger.info("NewForm" );
}
}
this will map both request POST and GET to the url
http://host:port/yourapp/yourEntryPoint
and this will map to GET
http://host:port/yourapp/yourEntryPoint/new

Spring 3 MVC, multipart form and controller mapping issue

My application uses submit name as action name consistently. It has worked so far.
Enter multipart form...
html
<form:form modelAttribute="screenObject" enctype="multipart/form-data">
<input name="save" value="Save" type="submit" />
Controller
public static final String ACTION_SAVE="save";
#RequestMapping(method=RequestMethod.POST, params=ACTION_SAVE)
public ModelAndView save(#ModelAttribute("screenObject") FileHeaderEditScreenObject screenObject, BindingResult bindingResult, Model model, Locale locale) {
Error
message Request method 'POST' not supported
If I remove enctype="multipart/form-data", control flows right into the save method. I do need different actions on this multipart form. I want to stay consitent so I hope I do not have to introduce any hidden fields to represent actions or submit the form to different urls...
I suggest to remove params=ACTION_SAVE from the annotation.
It look like that it doesn't parse submit action from a multipart request.
You can handle that parameter as a request parameter:
#RequestMapping(method=RequestMethod.POST, params=ACTION_SAVE)
public ModelAndView save(
#RequestParam(value = "submit", required = true) String action,
#ModelAttribute("screenObject") ....
{
switch (action) {
case "action1": ...
case "action2": ...
}
}
This is not very nice. I would just use different URLs like this:
#RequestMapping("/action1"})
public void action1(
#RequestMapping("/action2"})
public void action2(

send an object via post

I want to make a form in which I can update my entity in my REST application. For example I have a User entity whith username and realname fields.
Do I need in my request method do something like this
#RequestMapping(value = "/admin/user/update", method = RequestMethod.POST)
public String updateHouse(#RequestBody String username, #RequestBody String realname, Model model)
??
I would prefer to make something like this
#RequestMapping(value = "/admin/house/update", method = RequestMethod.POST)
public String updateHouse(#RequestBody User user, Model model)
I mean that I want to send an object not every field. If i`ll have 20 fields in my entity I would have to add 20 params to my method. Thats not to fancy.
I`m using spring form tag
------- UPDATE
thanks for response. below diffrent entity but real case scenario that i`m trying to start
html code
<c:url var="houseUpdateLink" value="/admin/house/update" />
<form:form method="post" commandName="house" action="${houseUpdateLink}">
<form:input path="house.title" />
<input type="submit" value="send" />
</form:form>
controller method
#RequestMapping(value = "/admin/house/update", method = RequestMethod.POST)
public String updateHouse(#RequestBody House house, Model model) {
model.addAttribute("step", 3);
logger.info("test: " + house.getTitle());
return "houseAdmin";
}
and i receive
HTTP Status 415 -
type Status report
message
description The server refused this request because the request entity is in a format not supported by the requested resource for the requested method ().
You don't need #RequestBody here. Spring will automatically bind the form fields to the House class without it, i.e.
#RequestMapping(value = "/admin/house/update", method = RequestMethod.POST)
public String updateHouse(House house, Model model) {
In the Spring form tags, you can probably do user.username, and pass the User object as a param.

Spring MVC form:errors not showing up

Apologies if this question has been asked before. I'm hoping that someone can step in and help me figure out why my form validation errors aren't showing up.
I'm using Spring 3.0.3 and Hibernate, and I'm using jsr-303 validation to validate my form inputs. I have a Spring controller that handles GETting a page that contains a form that is created with the help of Spring's form taglib. In this form a user is able to change their name and have it saved to the database. If any of the input is empty then the page with the form should be displayed again with error messages. The same controller handles the page's submission. It seems that the controller is functioning properly in most respects, but when there is an error in the user submitted form, no errors are showing up on the page.
Here is what form looks like:
<form:form commandName="changeNameCommand">
<form:errors path="*" cssClass="errorBox" />
<table width="100%" border="0" cellspacing="5" cellpadding="5" align="left">
<tr>
<td><b>First Name:</b></td>
<td><form:input path="firstName" value="${user.firstName}" /></td>
</tr>
<tr>
<td><b>Last Name:</b></td>
<td> <form:input path="lastName" value="${user.lastName}" /></td>
</tr>
</table>
</form:form>
Note that there is a user object in the view that is used to populate the form with the user's current first and last name. This is working properly.
The controller looks something like this:
#Controller
#RequestMapping(value = "/account/settings/change-name")
#SessionAttributes("changeNameCommand")
public class ChangeNameController {
#ModelAttribute("changeNameCommand")
public ChangeNameCommand getCommand() {
return new ChangeNameCommand();
}
#RequestMapping(method = RequestMethod.GET)
public ModelAndView getChangeNamePage(HttpServletRequest req) {
ModelAndView mav = new ModelAndView("Account.ChangeName");
mav.addObject("page_title", "Change Name");
return mav;
}
#RequestMapping(method = RequestMethod.POST)
public String doChangeName(
#ModelAttribute("changeNameCommand")
#Valid ChangeNameCommand command,
BindingResult result, SessionStatus status) {
if (result.hasErrors()) {
return "redirect:/account/settings/change-name";
}
// Code here to persist updated user first and last name to database...
status.setComplete();
return "redirect:/home";
}
}
I'm using Tiles 2.1.2 to compose pages and Urlrewrite 3.1.0 to help form friendly urls.
The ChangeNameCommand class looks something like this:
import org.hibernate.validator.constraints.NotEmpty;
public class ChangeNameCommand {
#NotEmpty(message = "You must provide a first name.")
private String firstName;
#NotEmpty(message = "You must provide a last name.")
private String lastName;
#NotEmpty(message = "Your password is required to make changes.")
private String currentPassword;
// Getters and setters here...
}
When debugging, I see that when there is not input for either the first or last name the BindingResult instance does contain errors. My concern is the redirect when there is an error. I've seen other questions here that just return the view name instead of using the redirect: prefix. I tried that but (I think) because of the way I'm using Urlrewrite and the way my servlet mapping is set up Spring returns an error. I've tried returning
/account/settings/change-name
/web/account/settings/change-name
/mywebsite/web/account/settings/change-name
but to no avail. FWIW, here is my servlet-mapping:
<servlet-mapping>
<servlet-name>mywebsite</servlet-name>
<url-pattern>/web/*</url-pattern>
</servlet-mapping>
Any help much appreciated!
using redirect makes all request attributes (including errors and the whole model) disappear. So, don't use redirect, or use the session to temporarily store the data, or use conversations. Or figure out how to use something like a flash-scope (I'm about to in a while)
Another thing - using UrlRewriteFilter with spring-mvc is uncalled for. You have full control over your beatuful REST-like URLs with spring-mvc only.
Here is how I solved my problem. To start off with, I didn't want to drop my use of UrlRewriteFilter and Tiles. However, the problem with this was that, in the case of errors, I couldn't just return the path, as indicated in the controllers RequestMapping annotation. Below is my solution, with the redirect removed in the case of errors, in doChangeName().
#Controller
#RequestMapping(value = "/account/settings/change-name")
#SessionAttributes("changeNameCommand")
public class ChangeNameController {
#ModelAttribute("changeNameCommand")
public ChangeNameCommand getCommand() {
return new ChangeNameCommand();
}
#RequestMapping(method = RequestMethod.GET)
public ModelAndView getChangeNamePage() {
ModelAndView mav = new ModelAndView("Account.ChangeName");
mav.addObject("page_title", "Change Name");
return mav;
}
#RequestMapping(method = RequestMethod.POST)
public ModelAndView doChangeName(#ModelAttribute("changeNameCommand") #Valid ChangeNameCommand command,
BindingResult result, SessionStatus status) {
if (result.hasErrors
ModelAndView mav = new ModelAndView("Account.ChangeName");
mav.addObject("page_title", "Change Name");
return mav;
}
// Code here to persist updated user first and last name to database...
status.setComplete();
RedirectView view = new RedirectView("/home");
return new ModelAndView(view);
}
}
Thanks to everyone who helped me out on this!

Resources