Action with 'wildcard' parameter in struts.xml and its annotation equivalent - java

I have an action defined in struts.xml which deletes a record on the database. However, I would like to map this action using annotations. This contains a "wildcard" parameter (the id of the record to be deleted). I am not quite sure how could this be when using annotations.
The action in struts.xml is as follows:
<action name="delete/*" class="RecordAction" method="deleteRecord">
<param name="record.id">{1}</param>
<result type="redirect">/table.html</result>
</action>

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.

How to work with view in Struts 2?

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.

Struts2 Is there a way to add metadata to action definition in struts.xml file?

I use the Struts2 framework to create a webapp. I have an interceptor that should have different behaviour depending on which action is invoked. For example, a login interceptor that should always allow some actions to execute, but it should block other actions if the user is not yet logged in.
The way I solve this now is by manually checking the name (and/or namespace) of the action in the interceptor, and determine my behaviour based on that. The downside of this "hardcocded" logic is that it is hard to maintain if I edit my struts.xml file, and it is also not obvious what is going on for other developers.
I would like to know if these is some way to add 'metadata' INSIDE the struts.xml file (or other file?) to "mark" certain actions as being certain "type". For example, something like this:
Struts.xml
<action name="loginPage" types="login, user, viewpage" class="login.controller.LoginPage">
<result name="success">/login/jsp/Login.jsp</result>
</action>
And then in my interceptor class:
#Override
public String intercept(ActionInvocation invocation)
throws Exception
{
Set<String> actionTypes = invocation.getInvocationContext().getTypes();
if(actionTypes.contains("login")
{
doSomething();
}
else
{
doSomethingElse();
}
}
Is this possible, or is the hardcoded parsing of name(space) the only way?
Obviously you can't do that because the DTD won't allow you.
Another good example of the XY problem:
The XY problem is asking about your attempted solution rather than your actual problem.
That is, you are trying to solve problem X, and you think solution Y would work, but instead of asking about X when you run into trouble,
you ask about Y.
What you really need is to define a group of actions running free, and other groups running under login control.
For this, you can manually include the Interceptor in each single action (useful when using the Convention plugin, a waste of time otherwise), or configuring the actions logically in the struts.xml.
The <package> is your friend here: define two (or more) packages, one running with the default settings, the other running your custom Interceptor for each action of the package:
<package name="unsecure-package" namespace="/unsecure" extends="struts-default">
<action name="login" class="org.foo.bar.actions.LoginAction">
...
</action>
<action name="askHelp" class="org.foo.bar.actions.AskHelpAction">
...
</action>
</package>
<package name="secure-package" namespace="/secure" extends="struts-default">
<interceptors>
<interceptor name="authInterceptor"
class="org.foo.bar.interceptor.AuthInterceptor"/>
<interceptor-stack name="securedStack">
<interceptor-ref name="authInterceptor"/>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="securedStack"/>
<action name="write" class="org.foo.bar.actions.WriteAction">
...
</action>
<action name="delete" class="org.foo.bar.actions.DeleteAction">
...
</action>
</package>
This way every time you or somebody else will add an Action in struts.xml, it will just need to drop it in the right package, and it will work automatically.
It's better to keep the Interceptor action-agnostic whenever possible ;)

How to set several action for a unique form using struts 1.3?

I'm developing a simple virtual store for an university project. I'm using struts 1.3. My problem is that I have this:
<action name="ComprarMaisForm" path="/ComprarMais" scope="session" type="com.myapp.struts.ComprarMaisAction">
<forward name="pagar" path="/pago.jsp"/>
<forward name="eliminar" path="/vistaCarrito.jsp"/>
<forward name="comprarmais" path="/index.jsp"/>
</action>
I want to have several actions instead of one. How can I do?
For different type of actions you have to specify different action mappings with different 'paths'
<action path="/goto1" ...> .. </action>
<action path="/goto2" ...> .. </action>
Anyways If You want to have several actions with same name (form-bean name) scope type and forward mappings (probably silly ques), You need the SAME action, just give same action name wherever you want to use it.
If any 1 parameter is different you need to specify different <action/> mappings.

Dynamically set value to static parameter in Struts 2

I was wondering, is it possible to dynamically set value to static parameter
<action name="TestApp_*" class="test.TestApp" method="{1}">
<param name="app_Id">Dynamic value here</param>
<result name="input">WEB-INF/jsp/test/testView.jsp</result>
</action>
I tried
<action name="TestApp_*" class="test.TestApp" method="{1}">
<param name="app_Id">${app_Id}</param>
<result name="input">WEB-INF/jsp/test/testView.jsp</result>
</action>
Not working. It shows ${app_Id} as regular text.
Note sure what exactly you mean by It shows ${app_Id} as regular text.Struts2 provide this flexibility where you can set param values dynamically.
All you need to set these values in your action class and you are all set to use them as a place holder.
public class MyAction extends ActionSupport {
private int app_Id;
public String execute() {
// you execute logic
this.app_Id= 123;
return SUCCESS;
}
// getter and setter for app_Id
}
And you can use this app_Id in your result configuration
<action name="TestApp_*" class="test.TestApp" method="{1}">
<param name="app_Id">${app_Id}</param>
<result name="input">WEB-INF/jsp/test/testView.jsp</result>
</action>
you can get more details parameters-in-configuration-results
You probably have written (erroneusly) the getter by hand, instead of letting the IDE do it for you.
A variable app_Id; must have a getter getApp_Id(), while you could have something like getapp_Id() or get_app_Id()... but how are we supposed to know it if you don't post your Action code ?!
Also, consider to change your variables (from now on) to respect the convention, that wants them camelCased, instead that underscore-separated... then appId for the variable and getAppId() for the getter.
try to do it like this way..
<result type="redirect">
<param name="location">WEB-INF/jsp/test/testView.jsp</param>
<param name="inputName">app_Id</param>
</result>
in the jsp page you can directly use this value like
<s:properties value="app_Id">
try this.
Look at the staticParams interceptor.
This interceptor populates the action with the static parameters defined in the action configuration. If the action implements Parameterizable, a map of the static parameters will be also be passed directly to the action. The static params will be added to the request params map, unless merge is set to false.
Parameters are typically defined with <param> elements within struts.xml.
It shows how to configure this interceptor to your action configuration.
For example:
<action name="someAction" class="com.examples.SomeAction">
<interceptor-ref name="defaultStack">
<param name="staticParams.parse">true</param>
<param name="staticParams.overwrite">false</param>
</interceptor-ref>
<param name="num">${numValue}</param>
<result name="success">good_result.ftl</result>
</action>
This enables the interceptor to parse parameter values for OGNL expression from the action configuration.

Categories