POST and GET for the same URL - Controller - Spring - java

I have this Controller :
#Controller
public class HelloWorldController {
#RequestMapping("/hello.html")
public ModelAndView helloWorld() {
String message = "Hello World, Spring 3.0!";
return new ModelAndView("hello", "message", message);
}
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String viewLogin(Map<String, Object> model) {
User user = new User();
model.put("userForm", user);
return "LoginForm";
}
#RequestMapping(value = "/login", method = RequestMethod.POST)
public String doLogin(#Valid #ModelAttribute("userForm") User userForm,
BindingResult result, Map<String, Object> model) {
if (result.hasErrors()) {
return "login";
}
return "LoginSuccess";
}
}
I have 2 methods having different http methods for the same url /login
so when clicking on the first url 'localhost:8080/project_name/login' the first method with GET will be handled and will redirect me to the /LoginForm
So from my understanding the second method handler will not be executed as the request for /login is always with GET.
If my understanding is wrong please explain to me how can the second method will be exectued and thanks.

the request for /login is always with GET
I think this is where you are getting confused. It's GET because the browser makes a GET call by default. If you want to evoke the second method, you may have to write a custom form / JSP page or check out postman to set the HTTP method to POST.
You can also use curl from command line:
$ curl -d "param1=value1&param2=value2" -X POST http://localhost:3000/data
If you want to be able to make POST calls from your browser itself, checkout these browser add-ons :
firefox, chrome,
If you do not like extensions in your browser, create a bookmark with the following text and use it :
javascript:var%20my_params=prompt("Enter%20your%20parameters","var1=aaaa&var2=bbbbb");%20var%20Target_LINK=prompt("Enter%20destination",%20location.href);%20function%20post(path,%20params)%20{%20%20%20var%20xForm=%20document.createElement("form");%20%20%20xForm.setAttribute("method",%20"post");%20%20%20xForm.setAttribute("action",%20path);%20xForm.setAttribute("target",%20"_blank");%20%20%20for(var%20key%20in%20params)%20{%20%20%20if(params.hasOwnProperty(key))%20{%20%20%20%20%20%20%20%20var%20hiddenField%20=%20document.createElement("input");%20%20%20%20%20%20hiddenField.setAttribute("name",%20key);%20%20%20%20%20%20hiddenField.setAttribute("value",%20params[key]);%20%20%20%20%20%20%20%20%20xForm.appendChild(hiddenField);%20%20%20%20%20}%20%20%20}%20%20%20document.body.appendChild(xForm);%20%20xForm.submit();%20}%20%20%20parsed_params={};%20my_params.split("&").forEach(function(item)%20{var%20s%20=%20item.split("="),%20k=s[0],%20v=s1;%20parsed_params[k]%20=%20v;});%20post(Target_LINK,%20parsed_params);%20void(0);

A hit from the browser for the url localhost:8080/project_name/login will be a GET call; so your first /login GET method will be executed.
To have the second method executed, make a POST call from any Rest client like PostMan or ARC etc.

click here
The Browser default choose the GET method . so if you try in postman you can see the difference. you have option to choose GET / POST.
For realtime also from the UI they will mention specific to GET request / Post request so no worries.
you can use the postman for better way

Related

Redirect to external URL from request mapping method in spring

Below is the request mapping method:
#GetMapping("/redirect")
public ResponseEntity<Void> redirect() {
String url = "http://yahoo.com";
return ResponseEntity.status(HttpStatus.FOUND)
.location(URI.create(url))
.build();
}
When I hit the URL http://somehost:8080/redirect in the browser I see that it takes me to yahoo.com, but when the /redirect is called from the UI(reactjs) the 302 Found httpstatus value is returned in the browser console but the page on the browser is blank. I was expecting to see the yahoo.com page. Seems it is not redirecting.
I referred this link: Redirect to an external URL from controller action in Spring MVC
reactjs code:
yield globalAxios.get(http://somehost:8080/redirect)
Below image when the http://somehost:8080/redirect gets called from the UI
Below image is when we the /redirect redirects to the link: yahoo.com
Is it because of the 405 method not allowed error as seen in the above image
Just in case if someone run into something like this in the future.
I end up using this code getting rid of 405 method not allowed while I am doing PUT-REDIRECT-GET pattern.
Notice it is #Controller and not #RestContorller. Otherwise it won't work.
If this is to be implemented in an existing rest controller you may want to add #ResponseBody over the other methods but not on these.
#Controller
#RequestMapping("/redirect")
public class RedirectController {
#PutMapping()
public String redirect() {
return "redirect:/redirect";
}
#GetMapping()
public String redirectPost() {
return "redirect:https://www.google.com";
}
}

response.sendredirect not working in external application

Response.sendRedirect(URL) is NOT working when I call from an external application. I am working on two enterprise applications parallelly.
Application A: http://localhost:9080/abc
Application B: http://localhost:8080/xyz
Angular App which is retrieving response from Application B: http://localhost:9000
Currently, I am in App-A and making AJAX call to App-B. When service hit to App-B RestController, then I want to redirect to http://localhost:9000 in browser from RestController of App-B.
I tried the below approach in RestController of App-B, but it doesn't work. Still, browser URL is http://localhost:9080/abc which is point to App-A:
#RequestMapping(value = "/redirect", method = RequestMethod.GET)
public void method(HttpServletResponse httpServletResponse) {
httpServletResponse.setHeader("Location", "http://localhost:9000");
httpServletResponse.setStatus(302);
}
#RequestMapping(value = "/redirect", method = RequestMethod.GET)
public ModelAndView method() {
return new ModelAndView("redirect:http://localhost:9000");
}
#RequestMapping(value = "/redirect", method = RequestMethod.GET)
public void method(HttpServletResponse httpServletResponse) {
httpServletResponse.sendredirect("http://localhost:9000");
}
I need to pass data from App-A to App-B before I launch angular application. So, I am making AJAX call from App-A. I can not directly call to Angular app from App-A with passing query param. I have to pass data through the header or request body.
Could you help with this?
A redirection response to an ajax request does not automatically cause a page to redirect. You need to manually fire the redirect in your response handler.
See Redirecting after Ajax post.

Redirect still remains in the same page in Spring MVC

I want to redirect to my home page, but this doesn't work:
#RequestMapping(value = "logout", method = RequestMethod.GET)
public String logout(HttpSession session) {
this.setSessionAccount(session, null);
return this.getRedirect("/index");
}
My current page is host/u/center. There's some response record:
You should
return "redirect:/index"
instead of calling another method of the controller.
I know what's the problem.
I use an ajax get request.
So I still remains in the same page.
Anyway,tanks for your answers.

Browser back button getting in to GET method of Spring MVC Controller instead of checking the cache

I am using Spring MVC 2.5. I have get and post methods for all the pages I have.
#RequestMapping(value = "/offer", method = RequestMethod.GET)
public ModelAndView getOffer(ModelMap model, HttpSession session) {
//code
return new ModelAndView(OFFER_SETTING_PAGE, model);
}
#RequestMapping(value = "/offer", method = RequestMethod.POST)
public ModelAndView postOffer(ModelMap model, #ModelAttribute("investorsEligiblitySetting")
//code
return new ModelAndView("redirect:/servlets/ProcessAction/privateplacement/createoffer/additionalinformation");
}
After passing the post method and displaying the next jsp file, when I try to hit the back button , instead of displaying the previous data from the cache (which is what I am looking for) it gets in to the get method of the specified url and causes some problems.
How can I make my application to look for cache first instead of getting in to a get method?
This is an old question, but I found this post that gives some ideas as to how to prevent the browser from resubmitting on the back button. You could also set something in your form when you handle the POST that the GET handler can look at to see if the POST already ran.

Spring - Redirect after POST (even with validation errors)

I'm trying to figure out how to "preserve" the BindingResult so it can be used in a subsequent GET via the Spring <form:errors> tag. The reason I want to do this is because of Google App Engine's SSL limitations. I have a form which is displayed via HTTP and the post is to an HTTPS URL. If I only forward rather than redirect then the user would see the https://whatever.appspot.com/my/form URL. I'm trying to avoid this. Any ideas how to approach this?
Below is what I'd like to do, but I only see validation errors when I use return "create".
#RequestMapping(value = "/submit", method = RequestMethod.POST)
public final String submit(
#ModelAttribute("register") #Valid final Register register,
final BindingResult binding) {
if (binding.hasErrors()) {
return "redirect:/register/create";
}
return "redirect:/register/success";
}
Since Spring 3.1 you can use RedirectAttributes. Add the attributes that you want to have available before doing the redirect. Add both, the BindingResult and the object that you are using to validate, in this case Register.
For BindingResult you will use the name: "org.springframework.validation.BindingResult.[name of your ModelAttribute]".
For the object that you are using to validate you will use the name of ModelAttribute.
To use RedirectAttributes you have to add this in your config file. Among other things you are telling to Spring to use some newer classes:
<mvc:annotation-driven />
Now the errors will be displayed wherever you are redirecting
#RequestMapping(value = "/submit", method = RequestMethod.POST)
public final String submit(#ModelAttribute("register") #Valid final Register register, final BindingResult binding, RedirectAttributes attr, HttpSession session) {
if (binding.hasErrors()) {
attr.addFlashAttribute("org.springframework.validation.BindingResult.register", binding);
attr.addFlashAttribute("register", register);
return "redirect:/register/create";
}
return "redirect:/register/success";
}
In addition to Oscar's nice answer, if you are following that RedirectAttributes approach, do not forget that you are actually passing the modelAttribute to the redirected page. This means if you create a new instance of that modelAttribute for the redirected page (in a controller), you will lose the validation errors. So, if your POST controller method is something like this:
#RequestMapping(value = "/submit", method = RequestMethod.POST)
public final String submit(#ModelAttribute("register") #Valid final Register register, final BindingResult binding, RedirectAttributes attr, HttpSession session) {
if (binding.hasErrors()) {
attr.addFlashAttribute("org.springframework.validation.BindingResult.register", binding);
attr.addFlashAttribute("register", register);
return "redirect:/register/create";
}
return "redirect:/register/success";
}
Then you will probably need to do a modification in your register create page GET controller. From this:
#RequestMapping(value = "/register/create", method = RequestMethod.GET)
public String registerCreatePage(Model model) {
// some stuff
model.addAttribute("register", new Register());
// some more stuff
}
to
#RequestMapping(value = "/register/create", method = RequestMethod.GET)
public String registerCreatePage(Model model) {
// some stuff
if (!model.containsAttribute("register")) {
model.addAttribute("register", new Register());
}
// some more stuff
}
Source: http://gerrydevstory.com/2013/07/11/preserving-validation-error-messages-on-spring-mvc-form-post-redirect-get/
I would question why you need the redirect. Why not just submit to the same URL and have it respond differently to a POST? Nevertheless, if you really want to do this:
#RequestMapping(value = "/submit", method = RequestMethod.POST)
public final String submit(
#ModelAttribute("register") #Valid final Register register,
final BindingResult binding,
HttpSession session) {
if (binding.hasErrors()) {
session.setAttribute("register",register);
session.setAttribute("binding",binding);
return "redirect:/register/create";
}
return "redirect:/register/success";
}
Then in your "create" method:
model.put("register",session.getAttribute("register"));
model.put("org.springframework.validation.BindingResult.register",session.getAttribute("register"));
The problem is you're redirecting to a new controller, rather than rendering the view and returning the processed form page. You need to do something along the lines of:
String FORM_VIEW = wherever_your_form_page_resides
...
if (binding.hasErrors())
return FORM_VIEW;
I would keep the paths outside of any methods due to code duplication of strings.
The only way to persist objects between requests (ie a redirect) is to store the object in a session attribute. So you would include "HttpServletRequest request" in method parameters for both methods (ie, get and post) and retrieve the object via request.getAttribute("binding"). That said, and having not tried it myself you may need to figure out how to re-bind the binding to the object in the new request.
Another "un-nicer" way is to just change the browser URL using javascript
I don't know the exact issue with Google App Engine but using the ForwardedHeaderFilter may help to preserve the original scheme that the client used. This filter was added in Spring Framework 4.3 but some Servlet containers provide similar filters and the filter is self-sufficient so you can also just grab the source if needed.
Perhaps this is a bit simplistic, but have you tried adding it to your Model? I.e., include the Model in your method's arguments, then add the BindingResult to it, which is then available in your view.
model.addAttribute("binding",binding);
I think you may have to use a forward rather than a redirect (in my head I can't remember if a redirect loses the session or not — I could be wrong about this as I don't have any documentation handy, i.e., if you're not getting the BindingResult after adding it to the Model, try using a forward instead to confirm this).

Categories