RequestMapping in Controller in Spring MVC in getting changed sometimes - spring-mvc

I am trying to implement Spring MVC in my web application and I have a controller class.
#Controller<br>
public class ContactController {
#Autowired<br>
private ContactService contactService;
#RequestMapping("/login")
public String displayLoginPage(HttpServletRequest httpReq, #ModelAttribute("login") Login login, BindingResult result){
return "login";
}
/*Spring will automatically calls this method whenever it encounters "/home" url in request.*/
#RequestMapping("/login/home")
public String displayHomePage(HttpServletRequest httpReq, Map<String, Object> map){
map.put("contact", new Contact());
map.put("contactList", contactService.listContact());
return "contact";
}}
After launching the application, login screen comes up and then upon click of button, I am observing that value for RequestMapping is getting changed sometimes. Sometimes it is "/login/home" or sometimes it is "/home". Why this is not constant ? Is there any way so that I may know what will be the requestMapping so that I can forward it to corresponding method in controller ?
PS: In the login.jsp, I have code like below:
form action="home" commandName="login"

If form action doesn't begin with a slash (/), form is submitted to address relative to the current one.
If you are already on the login page (i.e. your current address already ends with /login) and you have specified form action="home", form is submitted to current address with home appended at the end - so the result is /login/home, which maps to one of your controller methods.

Related

PRG Pattern in ASP.Net MVC?

I'm new to ASP.Net MVC. In PHP, I always use the PRG pattern even when the post request was invalid. It was pretty easy with session flashes (also user friendly).
In ASP.Net MVC, however, I don't see an easy way to do PRG when the request is invalid. I could think of some ways, but I don't think they are good practices and put some extra unnecessary work.
Moreover, from a couple of articles that I've read, a PRG when the request was invalid was discouraged. If it's a bad practice, then what's the better way to handle unsuccessful post requests? Is it really better off without the PRG? And should I just let the rather annoying browser warnings when a user tries to refresh the page?
In Mvc, it's normal practice to handle your Post Actions as it follows:
[HttpPost]
[ValidateAntiForgeryToken]
public virtual ActionResult LoginForm(LoginViewModel loginViewModel)
{
if (!ModelState.IsValid)
return View("Login", loginViewModel);
return Redirect("/");
}
As you can see, the property ModelState.IsValid will tell you if the request is invalid, therefore giving you the ability to return the same view and display the error messages in the ValidationSummary when the Post request contains an error. This is the code for the View:
#using (Html.BeginForm("LoginForm", "Account"}))
{
#Html.ValidationSummary() // THIS WILL SHOW THE ERROR MESSAGES
#Html.AntiForgeryToken()
#Html.TextBoxFor(x => x.Email)
#Html.PasswordFor(x => x.Password)
<button type="submit">Submit</button>
}
We have been using PRG pattern in our asp.net mvc web apps for about 5 years. The main reason we adopted PRG was to support browser navigation (eg back, forward). Our web apps are used by customer and for front/back office operations. Our typical web page flow is starts with a login, then progresses via many list/detail view. We also incorporate partial views which also have their own viewmodel. List views will have links (GETS) for navigation. Detail views will have forms (POSTS) for navigation.
Keys aspects of our PRG:
We incorporate viewmodels so each view has a viewmodel (all data access is done in the viewmodel).
Each viewmodel has a set() & get() method to maintain the key data field values associated with the most recent instance of the view. The set/get values are persisted in sessionstate.
The set method has a parameter for each value that needs to be set. The get method is just called from the viewmodel constructor to populate the viewmodel's public "key" values.
The viewmodel will also have a public load() method that get all neccessary data for its view.
Our PRG pattern overview:
In controllers we have a separate GET method and a POST method for each action. The GET only displays a view; the POST processes the posted data.
For list (menu) views, the controller GET method calls the target view's set('item key values here') method, then invokes a RedirectToAction to to the target view's controller GET action.
The controller GET method will instantiate the viewmodel (thus causing get of set values), call its load method which uses the set/get key values to get it data, and returns the view/viewmodel.
The controller POST method will either have the viewmodel save the valid posted data then redirect to the next desired page (probably the previous list menu) -OR- if redisplay the current view if the data is invalid.
I have not documented all the PRG flow senarios that we implemented, but the above is the basic flow.
SAMPLE VIEWMODEL SET/GET METHODS
private void GetKeys() {
Hashtable viewModelKeys;
if (SdsuSessionState.Exists("RosterDetail"))
{
viewModelKeys = (Hashtable)SdsuSessionState.Get("RosterDetail");
EventId = (int)viewModelKeys["EventId"];
SessionNo = (int)viewModelKeys["SessionNo"];
viewModelKeys = null;
}
}
public static void SetKeys(int eventId, int sessionNo) {
Hashtable viewModelKeys = new Hashtable();
viewModelKeys.Add("EventId",eventId);
viewModelKeys.Add("SessionNo",sessionNo);
SdsuSessionState.Set("RosterDetail",viewModelKeys);
viewModelKeys = null;
}
SAMPLE CONTROLLER
[AcceptVerbs("Get")]
public ActionResult MenuLink(int eventId, int sessionNo, string submitButton) {
if (submitButton == RosterMenu.Button.PrintPreview) {
// P-R-G: set called viewmodel keys.
RosterDetail.SetKeys(eventId,sessionNo);
// Display page.
return RedirectToAction("Detail","Roster");
}
if (submitButton == RosterMenu.Button.Export) { etc ...}
}

How to call JSP from a java Controller

I have a simple J2EE application with Spring.
Now I want from Java controller call another page. For example, I'm in registrazione.jsp, I click on one button, and I call a method in registrazioneController.java.
Now I want from registrazioneController.java, call another page, for example
home.jsp and I want pass any parameter in get.
It is possible?
this is the method that I use when I click the button
registrazioenControlle.java
public ModelAndView internalLoadPage(HttpServletRequest request, HttpServletResponse response, Map model) throws Exception
{
//to do
//call another page for example home.html
request.getRequestDispatcher("home.jsp").forward(request, response);
return new ModelAndView("home", model);
}
I'm try to use this code but no found.
In addition to the answer provided in the comments, you can also use RedirectAttributes, and addAttribute method if you want to append a parameter to URL upon redirect. This will also give you the addFlashAttribute that will store the attributes in the flash scope which will make it available to the redirected page. You can also return a simple string as the view name e.g. like
public String internalLoadPage(RedirectAttributes redirectAttributes) throws Exception
{
redirectAttributes.addAttribute("paramterKey", "parameter");
redirectAttributes.addFlashAttribute("pageKey", "pageAttribute");
return "redirect:/home";
}
this assumes that the view suffix is configured in you view resolver configuration

Spring MVC - How to make sure that form submit path is not there in URL post form submit?

I have a question on Spring MVC. I have a form where I take some values from user. And then on submit call action (say addTaskAction). It calls the controller below. The controller does what it needs to do (add Task to database) and calls the view showTasks. Till now,everything is fine. But here is my problem. The URL still shows /addTaskAction. So if I do a refresh or F5, the controller is again called and another task is added to database.
What is the cleanest/industry standard way of avoiding this? How to make sure that post form submit the URL shows /showTasks and not /addTaskAction.
...
Add
#RequestMapping(value = "/addTaskAction", method = RequestMethod.POST)
public String addTaskAction(#RequestParam("issueType") String issueType,
#RequestParam("priority") String priority,
#RequestParam("summary") String summary,
#RequestParam("reporter") String reporter,
#RequestParam("assignee") String assignee,
#RequestParam("status") String status,
#RequestParam("comments") String comments,
Model model) {
System.out.println(issueType);
Task task = new Task(issueType,priority,summary, reporter,
assignee,status,comments);
taskRepository.save(task);
model.addAttribute("tasks", taskRepository.getAllTasks());
//model.addAttribute("task", task);
System.out.println("Tasks added-"+taskRepository.getAllTasks().size());
return "showTasks";
}
You're not supposed to return a page from a POST, you're supposed to redirect to a different page, thus changing the url. In your example, you should probably have something like this:
return "redirect:showTasks";
This returns a redirect instruction to the browser, that then requests the page you've specified.

MVC4 Action only triggers while debugging locally

I have an action I use to reset the password for my users:
public class Password : Controller{
public ActionResult Reset(string id)
{
//...
}
}
The id is actually the encrypted email address provided by the user when asked which email address the password recovery is for.
So, if I click on the "Forgot Password?" link, and provide the email address user#domain.com the resulting url sent to the user's email would be something like:
http://www.myapp.com/admin/password/reset/euPdxABQEgE0JDuv6OHSLnk1QBYf73YseBUZwR9+MJA=
That would be routed to the Reset action on the Password controller included above.
This is working fine while I'm debugging the app locally.
This is NOT working on my test server; I'm getting a 404 instead.
Interesting facts:
If I remove the Id from the url
http://www.myapp.com/admin/password/reset/ I get redirected to the
index action of the password controller with the proper message
"Invalid link" as expected.
I if include any other string in the id (ie: http://www.myapp.com/admin/password/reset/abc123) I get redirected as expected; as described in 1).
So it seems that this is somehow related with the anatomy of the id I'm passing around. I tried url encoding it but that didn't work.
This is the route definition for the Admin Area:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { controller = "Login", action = "Index", id = UrlParameter.Optional }
);
}
The main routes are the default ones.
Any ideas?
I suspect that this is because of the + sign in the path portion of your url. You may take a look at the following blog post in which Scott Hanselman explains the difficulties that you will encounter by attempting to pass such special characters in the path portion.
I will quote only his conclusion:
After ALL this effort to get crazy stuff in the Request Path, it's
worth mentioning that simply keeping the values as a part of the Query
String (remember WAY back at the beginning of this post?) is easier,
cleaner, more flexible, and more secure.
So simply drop that and use the following url:
http://www.myapp.com/admin/password/reset?id=euPdxABQEgE0JDuv6OHSLnk1QBYf73YseBUZwR9%2BMJA%3D
Notice how I url encoded the string which is what you should be doing when passing parameters as query string values in an url.

What's the best way to do a FormsAuthentication.SignOut() in MVC from within an action

I have a SignOut action inside a LoginController like so:
[Authorize]
public ActionResult SignOut()
{
var membershipProvider = new MembershipProviderFactory().Create();
membershipProvider.SignOut();
FormsAuthentication.SignOut();
return RedirectToAction("Index");
}
It's all working fine but I am concerned about the two round-trips back and forth between the client and the server that this method will cause.
First round-trip:
The FormsAuthentication.SignOut() calls GetDefaultLoginPage() (the one that's declared in the <forms> authentication element in the web.config file and does a response.redirect to that. That's already one 301/302 round-trip.
Second round-trip:
return RedirectToAction("Index") causes another one.
Ideally, the RedirectToAction("Index") call must be redundant because it is also redirecting the user to the default HttpGet action on the Login controller which will call the default Login screen view, which is the same as the default login page.
But if I exclude that RedirectToAction call from the SignOut action, I must return some ActionResult type. What should I return?

Resources