Control action method by GET or POST in struts2 - java

I'm new to Struts2, coming from a PHP background, where I'd often have the same file handling GET and POST requests, and processing a form if the request is a POST request.
I currently have the following in struts.xml:
<action name="ProcessData" class="ProcessDataAction">
<result name="*">processdata.jsp</result>
</action>
<action name="ProcessDataUpload" class="ProcessDataAction" method="upload">
<result name="*">processsdata.jsp</result>
</action>
Which works fine, but it bothers me that the URL that handles POST is different, since now if the user reloads the page, they get an error rather than simply seeing the contents of the GET page.
So my question is, is there any way to tell struts2 to call one method if it's a GET request, and another method if it's a POST request?

Struts2 doesn't offer what you described out of the box. If you want to enforce that a particular action method is invokable only by certain HTTP methods, then you'd need to create a custom interceptor and probably a few custom annotations.
If you just want the same action to handle displaying the form and processing it, then you can do the following:
public class MyAction {
public String execute() {
return INPUT;
}
public void validate() {
// perform any form validation needed
}
public String submit() {
// process the form and then redirect
}
}
In your form, you would submit to ProcessData!submit. The ! separates the action from the action method name. It provides what you have already, but you don't need to explicitly map each method in the struts.xml.
But it bothers me that the URL that handles POST is different, since now if the user reloads the page, they get an error rather than simply seeing the contents of the GET page.
Redirecting the user after a successful post completely nullifies this point. Look at the "Redirect After Post" or "Post/Redirect/Get" pattern).

Not by default, no. IMO the cleanest solution is to tweak the method name via an interceptor that looks at the request type. For example, I had a simple one that looked for executeGet and executePost methods.
Whether or not it's a great idea... different issue.

Related

Is it possible to prevent GET calls for particular actions in Struts 2?

in my application I send all forms as POST request :
<s:form method="POST">
however I noticed when I prepare GET call like this:
www.domain.com?method:Save&param1=aa
proper action is invoked.
My question: is it possible to prevent GET calls for particular actions ?
So if I run www.domain.com?method:Save&param1=aa , action "Save" would not be invoked?
You can add interceptor to intercept the action and if the method is not POST then return error result. If you want to learn how to configure the result you can read this answer.
In the interceptor implementation you can use ServletActionContext.getRequest() similar to this answer.
Then use request.getMethod() to get the method of HTTP request.

Call controller method from JSP button in Spring MVC

I would like to call a controller method using a button on a JSP page in Spring MVC, but I would like it to stay on a current page, don't reload it or anything, simply call a method. I found it difficult. My button is on cars.jsp page. In order to stay on this page I have to do something like this:
#RequestMapping(value="/start")
public String startCheckingStatus(Model model){
System.out.println("start");
model.addAttribute("cars", this.carService.getCars());
return "car\\cars";
}
button:
Start
But this is not a good solution because my page is actually reloaded. Can I just call controller method without any refreshing, redirecting or anything? When I remove return type like so:
#RequestMapping(value="/start")
public void startCheckingStatus(Model model){
System.out.println("start");
}
I got 404.
Add an onclick event on your button and call the following code from your javascript:
$("#yourButtonId").click(function(){
$.ajax({
url : 'start',
method : 'GET',
async : false,
complete : function(data) {
console.log(data.responseText);
}
});
});
If you want to wait for the result of the call then keep async : false otherwise remove it.
As mentioned elsewhere you can achieve this by implementing an Ajax based solution:
https://en.wikipedia.org/wiki/Ajax_(programming)
With Ajax, web applications can send data to and retrieve from a
server asynchronously (in the background) without interfering with the
display and behavior of the existing page. By decoupling the data
interchange layer from the presentation layer, Ajax allows for web
pages, and by extension web applications, to change content
dynamically without the need to reload the entire page.
To achieve this you will need to make changes to both the client and server side parts of your app. When using Spring MVC it is simply a case of adding the #ResponseBody annotation to your controller method which:
can be put on a method and indicates that the return type should be
written straight to the HTTP response body (and not placed in a Model,
or interpreted as a view name).
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-responsebody
Thus, for example, to return a simple String in the Ajax response we can do the following (without the #ResponseBody the framework would try and find a view named 'some status' which is obviously not what we want):
#RequestMapping(value="/start")
#ResponseBody
public String startCheckingStatus(Model model){
return "some status";
}
For the client part you need to add some javascript which will use the XMLHttpRequest Object to retrieve data from your controller.
While there are various frameworks which can simplify this (e.g. JQuery) there are some examples at the below using vanilla javascript and it might be worth looking at some of these first to see what is actually going on:
http://www.w3schools.com/ajax/ajax_examples.asp
If we take this specific example:
http://www.w3schools.com/ajax/tryit.asp?filename=tryajax_callback
and [1] copy the <button/> and <script/> elements to your JSP, [2] change the URL to point to your controller and, [3] create an element <div id="demo"></div> in your JSP then, on clicking the button in your page, this <div/> should be updated to display the String returned by your controller.
As noted this is a lot of code for one action so you can use some JS framework to abstract a lot of it away.

Struts 2 Validation clearing out url parameter

If I am at http://foo.bar?fooId=123 and the validation fails (validate method in action class) I get redirected to http://foo.bar without the fooId param. This causes form fields to lose their values. Any ideas why this is happening?
You are using GET to send your parameters, server on validation failure is sending you the same input page, instead of GET use POST and everything should work fine.
Your configuration would look like this :
<result name="input">inputPage.jsp</result> which discards any parameter that you submitted.
Also note as per HTML specification GET shouldn't be called if operation will result in any updatation, instead POST should be used.

Spring Ajax controller - Accept submissions without refreshing page

I am using Starbox in my Spring page. I want to submit the user rating so I can store it in the database and not have to refresh the page for the user. How can I have a Spring controller that accepts this value and doesn't have to return a new view. I don't necessarily need to return any updated html - if the user clicks the Starbox, that is all that needs to happen.
Similarly, if I have a form with a submit button and want to save the form values on submit but not necessarily send the user to a new page, how can I have a controller do that? I haven't found a great Spring AJAX tutorial - any suggestions would be great.
If you use annotations, perhaps the more elegant way to return no view is to declare a void-returning controller method with #ResponseStatus(HttpStatus.OK) or #ResponseStatus(HttpStatus.NO_CONTENT) annotations.
If you use Controller class, you can simply return null from handleRequest.
To post a from to the controller via AJAX call you can use the appropriate features of your client-side Javascript library (if you have one), for example, post() and serialize() in jQuery.
The AJAX logic on the browser can simply ignore any data the server sends back, it shouldn't matter what it responds with.
But if you really want to make sure no response body gets sent back, then there are things you can do. If using annotated controllers, you can give Spring a hint that you don't want it to generate a response by adding the HttpServletResponse parameter to your #RequestMapping method. You don't have to use the response, but declaring it as a parameter tells Spring "I'm handling the response myself", and nothing will be sent back.
edit: OK, so you're using old Spring 2.0-style controllers. If you read the javadoc on the Controller interface, you'll see it says
#return a ModelAndView to render, or
null if handled directly
So if you don't want to render a view, then just return null from your controller, and no response body will be generated.

The indestructibles - HTTP Parameters

I always wondered why there exists no removeParameters() method in Servlet API.
What could be the motive behind this design?
Here is a scenario: I am posed with a challenge in a proprietary MVC framework that I am compelled to use. This framework uses a Controller Servlet that hosts an algorithm in it's post method:
doPost() {
//create instance of action - just like struts action
action.init
action.preexecution
if(redirection state is not set)
action.process
action.postprocess
action.finish
}
The only way I can skip process of any particular action would be by setting a redirection url. The Controller Servlet is FINAL. Now, when I do a requestdispatcher.forward from say the preexecution method of an action, the controller will go ahead and execute the rest of the methods and not skip the rest. I cannot change this behavior, neither can I set the redirect, coz I need to do a forward. It works fine as long as I am not forwarding request to the same action. When a request is forwarded to the same action, the http parameters are all the same. This would take it into a never ending loop. Hence, I am compelled to add extra parameters indicating that it is a repeat request and should be treated differently.
Not sure if my problem made sense, but thought this is a good forum to post the same.
Umm... because it would serve no purpose? Request parameters are sent by the client to the server. The server is free to ignore them, but what practical effect would you expect such a removeParameter() method to have?
Edit: Request parameters are meant for the communication between server and client. For server-internal communication, you can use request attributes, which can be set and removed.
EDIT: McDowell reminded me of HttpServletRequestWrapper, so I'm changing the below to make it a little less work... Thanks McD!
You can decorate the request to "hide" parameters you don't want and/or add extra parameters.
Something like (off the top of me head -- no compiling so the API might be a tweak off...)
public class MyParameterHider extends HttpServletRequestWrapper {
public MyParameterHider(HttpServletRequest request) {
super(request);
}
public String getParameter(String name) {
if ("parameterToHide".equals(name))
return null;
return realRequest.getParameter(name);
}
// similar for getParameterNames and getParameterMap - don't include the hidden parm
// all other methods are strictly pass-through and are automatically
// handled by HttpServletRequestWrapper
}
In your forward, just wrap the request in a ParameterHider when calling doFilter:
dispatcher.forward(new MyParameterHider(request), response);
Patterns FTW!
Hope this helps!

Categories

Resources