How to work with view in Struts 2? - java

In plain old servlets I can use doGet and doPost methods. Where in doGet i'm forwarding user to some page and in doPost i'm proccessing data entered from the page that I gave. That all happening in one servlet.
But the Struts2 works on Front Controller pattern and instead doGet/doPost I have only execute method. So how can I properly give user some page, so then he can see it, enter data, submit and application as result proccess it in execute ?
From what I know I have two options (example on registration form):
Map page to another url:
<action name="register_display">
<result name="success" type="dispatcher">register.jsp</result>
</action>
<action name="register"
class="magazine.action.client.RegisterClientAction"
method="execute">
<result name="success" type="redirectAction">/index</result>
<result name="error" type="redirectAction">register_display
</result>
</action>
Create whole package named display and place there all view from which POST can be performed:
<package name="display" namespace="/display" extends="struts-default">
<action name="register">
<result name="success" type="dispatcher">register.jsp</result>
</action>
...
</package>
Is there any other options ? Which one is prefered ?

In the standard Struts2 style, an Action class has only one work method, this is the execute method. However, you do not necessary have to follow this. You can define multiple actions in a single Action class.
For example you make a GET request to users, which is handled in the default execute method of UsersAction.
#Override
public String execute() {
// fetch the list of users
return SUCCESS;
}
Let's suppose you would like to add a new user in this same action, by POSTing to user_add. So you define an add method:
public String add() {
// add the user
return SUCCESS;
}
The struts.xml would look similar to this:
<package name="users" extends="defaultPackage">
<action name="users" class="com.example.UsersAction">
<result>users.jsp</result>
</action>
<action name="user_add" class="com.example.UsersAction" method="add">
<result type="redirect">users</result>
</action>
</package>
In your scenario, you would render your page, which the user should see after the run of the (maybe empty) execute method. Then, you would make the post request, which would be mapped to the other method of the Action class.

Related

Struts2 2.5 - Multiple actions in same form

I want to call to different actions in the same form. In a previous app I developed it works nice,(see code below), but now I have switched versions from Struts 2.1.6 to 2.5.8 and it's not working.
In the answer of this question, the use of different actions in the same form is discouraged. Instead, the author proposes to call different methods inside the same action. That's fine, but in my app I need to call these actions/methods from several places, not only this form, so I would prefer to separate the action calls in the struts.xml file.
Note: I'm calling "action" from the struts.xml point of view. Each action calls to a different method from the same class *Action.java. All actions of this .java class are grouped in the same package of the struts.xml
Form in list.jsp:
<s:form name="changeStatusForm" theme="simple" id="formList">
<s:hidden id="idSelectedRow" name="idSelectedRow"/>
<s:submit key="global.showMore" action="showMore" />
<s:submit key="global.edit" action="edit"/>
<s:submit key="global.delete" action="delete"/>
</s:form>
The jsp is a list of objects. When I click in one row, a menu with several options appear (the ones of the form). The id of the desired object is gathered in the variable idSelectedRow.
struts.xml
<package name="object" namespace="/object" extends="authenticate-default">
<result-types>
<result-type name="tiles" class="org.apache.struts2.views.tiles.TilesResult"/>
</result-types>
<global-results>
<result name="error" type="tiles">error</result>
<result name="errorLogin" type="tiles">errorLogin</result>
</global-results>
<action name="list" method="list" class="actions.ObjectAction">
<result name="success" type="tiles">listObject</result>
<result name="input" type="redirect">list</result>
<result name="error" type="tiles">listObject</result>
</action>
<action name="showMore" method="showMore" class="actions.ObjectAction">
<result name="success" type="tiles">showMore</result>
</action>
<action name="edit" method="edit" class="actions.ObjectAction">
<result name="success" type="tiles">edit</result>
</action>
<action name="delete" method="delete" class="actions.ObjectAction">
<result name="success" type="tiles">list</result>
</action>
.
.
.
</package>
Object.java:
public class ObjectAction extends BaseActionCRUD implements ModelDriven<ObjectDTO> {
...
public String showMore() {
...
return SUCCESS;
}
public String edit() {
...
return SUCCESS;
}
public String delete() {
...
return SUCCESS;
}
public String list() {
...
return SUCCESS;
}
...
}
So, how can I do this same thing in Struts 2.5.8?
Right now, the method executed in ObjectAction.java is always list() instead of the selected one. That's because the action that redirects to list.jsp is list.
Thanks!
Extremely important: migrate to 2.5.10.1, not to 2.5.8. Any 2.5 version prior to 2.5.10.1 (and any recent 2.3 version prior to 2.3.32) is vulnerable to a critical security issue, S2-045.
Since 2.3.15.3, you need to explicitly enable the action: prefix (that is generated by the action="" attribute in the <s:submit> tags) in struts.xml with:
<constant name="struts.mapper.action.prefix.enabled" value="true"/>
The method="" prefix, called DMI (Dynamic Method Invocation), which usage is suggested in the 2011's answer you've linked, it is now deprecated and completely discouraged.
Also the action: prefix method is discouraged against more robust solutions (like changing the target of the <form> with Javascript according to which of the <submit> buttons has been pressed) but, if you want, you can still enable and use it, there are no big problems with it.

browser asks to resend data when page is reloaded

I am writing an application using struts2. I am facing a problem in the login part. When a login is performed,it will redirect to the index.jsp page.Now the problem arises. The problem is when after loggin in, index.jsp is reloaded, browser asks me resend data. I dont know why it is happening?
here is my struts.xml code for authenticate action:-
<action name="authenticate" class="com.action.LoginAction">
<result name="success">index.jsp</result>
<result name="failure">loginerror.jsp</result>
</action>
and here is code for the login action class:-
public String execute() {
if(sessionMap.containsKey("project_user")){
return "success";
}
Project_User project_User=Login.checkCredentials(email_id,password);
if(project_User!=null) {
sessionMap.put("project_user", project_User);
return "success";
} else
return "failure";
}
also when index.jsp comes, the url area of browser remians unchanged, the link in url field of browser still shows the action name like:- localhost:8084/Tek-Hub/authenticate/
if anyone knows about it plzzz help me.
Thanxx
You need to use a pattern named PRG (Post / Redirect / Get).
This way, a second request will be performed when executing the first action result (because of the redirection), and a refresh of the landing page (eg. pressing F5) will hit the second action (the GET one), instead of the login action (the POST one).
Change this:
<action name="authenticate" class="com.action.LoginAction">
<result name="success">index.jsp</result>
<result name="failure">loginerror.jsp</result>
</action>
to this:
<action name="authenticate" class="com.action.LoginAction">
<result name="success" type="redirectAction">index.action</result>
<result name="failure">loginerror.jsp</result>
</action>
<action name="index" class="com.action.IndexAction">
<result name="success">index.jsp</result>
</action>

What happens when in struts configuration "xyz.do" is in forward path?

This is a sample code from config file.
<action path="/admin/reloadLogging"
type="com.sap.isa.core.logging.ReloadLoggingAction">
<forward name="success" path="/b2b/init.do"/>
</action>
I did not find any specific configuration for /b2b/init.do.
So my question is, where the request will be forwarded??
There is no JSP for it. Will it go again to the Action class?
This request will be forwarded to the action class/servlet that handles the "b2b/init.do" request.
For example if you forwarded to the same url "reloadLogging" then you will find yourself in an infinite loop and get a "StackOverflow" error.
<action path="/admin/reloadLogging"
type="com.sap.isa.core.logging.ReloadLoggingAction">
<forward name="success" path="/admin/reloadLogging.do"/>
</action>

Using struts2 to redirect with dynamic parameters not working

I'm having an issue while trying to redirect mapping with dynamic parameters.
The way I'm mapping in Struts2:
<action name="Delete" class="templateLalaAction" method="remove">
<result name="success" type="redirect-action">
<param name="actionName">LalaTemplatesDisplay</param>
<param name="buId">${buId}</param>
</result>
<result name="failure" type="redirect-action">
LalaTemplatesDisplay
</result>
</action>
The method "remove" in the action:
remove() {
putRequestAttribute("buId",Long.valueOf("1111"));
return SUCCESS;
}
if I do this, I'm setting the buId=1111, but when I run the app, the url ends with buId= (it's empty), i.e., no parameter is being passed.
if I comment the putRequestAttribute method, and set struts passing buId parameter as a static value:
<action name="Delete" class="templateLalaAction" method="remove">
<result name="success" type="redirect-action">
<param name="actionName">LalaTemplatesDisplay</param>
<param name="buId">1111</param>
</result>
<result name="failure" type="redirect-action">
LalaTemplatesDisplay
</result>
</action>
It works and the url ends with buId=1111.
I also read this question where the accepted answer teaches us to do the same I did, but if we read the comments the user did, we'll see he has the same problems I have. What am I possibly doing wrong?
Inside your method just assign buId variable and you need getter/setters for it in your action class.
public String remove() {
buId = 1111l;
return SUCCESS;
}
Also you are using old syntax for redirect-action, use camel case redirectAction.

Stop user from accessing a Struts2 action directly?

I have the following actions defined in my struts.xml
<action name="Search" method="prepareLookUpvalues" class="com.mycompany.actions.FrSearchAction">
<result name="success" type="tiles">search.layout</result>
</action>
<action name="List" class="com.mycompany.actions.FrSearchAction">
<result name="success" type="tiles">results.layout</result>
<result name="input" type="tiles">search.layout</result>
</action>
<action name="SearchDetails" class="com.mycompany.actions.FrSearchDetailsAction">
<result name="success" type="tiles">details.layout</result>
</action>
<action name="Logoff" class="com.mycompany.actions.LogoffAction" >
<result name="success" type="tiles">logoff.layout</result>
</action>
Assuming that a user goes directly to my page home http://localhost:8080/fr/Search.action everything works OK, but it has been discovered hat some users are accessing http://localhost:8080/fr/List.action directly without first going to the search page which is causing problems.
When a user goes to the search page and enters criteria and submits, it is only then that the "List" action should be called via the struts form's action attribute. I basically want to stop users from being able to access the "List", "SearchDetails", and "Logoff" actions directly unless those actions are invoked from my JSPs or code.
I'm new to maintaining/developing Struts2 applications and I haven't found clear answers to this. Any suggestions would be greatly appreciated!
There's a few details missing so the answer will be a bit vague, but the list action probably pulls values from a form submission to search? Or pulls state from session? Or...?
Anyways, however that may be stored, simply check and then redirect the user to Search if the state is not set as expected.
For details on doing redirects in struts2, see, for e.g. http://www.roseindia.net/struts/struts2/actions/struts-2-redirect-action.shtml
This isn't an elegant solution but you could try checking for the referer to see who called the action. You action class will need to implement ServletRequestAware.
String referrer = request.getHeader("referer");
if (referrer.equals("http://localhost:8080/fr/Search.action")) {
// do the action
} else {
// handle unwanted access
}
Remember that the referer is a client-controlled value and can be spoofed or removed.

Categories