struts2 - understanding the value stack - java

I have a question regarding the struts2 value stack. Let's say I have an Action class called RegisterAction that has an execute method as follows:
public String execute() {
ValueStack stack = ActionContext.getContext().getValueStack();
stack.push(new String("test string"));
return SUCCESS;
}
My struts.xml looks like this:
<struts>
<package name="default" extends="struts-default">
<action name="*Register" method="{1}" class="vaannila.RegisterAction">
<result name="populate">/register.jsp</result>
<result name="input">/register.jsp</result>
<result name="success">/success.jsp</result>
</action>
<action name="*Test" method="{1}" class="vaannila.TestAction">
<result name="test">/test.jsp</result>
<result name="success">/success2.jsp</result>
</action>
</package>
</struts>
So control will flow to the success.jsp after the execute method executes in that class.
My questions are:
1) how do I get that value I pushed on the stack in the success.jsp?
2) Let's say in success.jsp I have a <s:submit method="testMethod" /> that redirects to an action class called TestAction. In other words, from the Register page, the user clicks submit, and in the execute method of the RegisterAction we push the "test string" on the stack. Then we go to success.jsp. The success.jsp has a submit button that directs us to TestAction#testMethod. In TestAction#testMethod, is the value I pushed on the stack in RegisterAction#execute still there? How can I get it? I stepped through the eclipse debugger but I don't see the value.
Thanks.

Ok, I figured this out.
1) The way I found to get objects on the value stack so we can access them from a jsp is like this:
Map<String, Object> context = new HashMap<String, Object>();
context.put("key", "some object");
context.put("key2", "another object");
ActionContext.getContext().getValueStack().push(context);
In other words, we can put a HashMap on the value stack containing the objects we need. Then, in the jsp, we can access the actual values like this:
<s:property value="key" />
<s:property value="key2" />
It will look through the value stack and find those values in the HashMap we pushed.
2)
An instance of the action class is associated with just one request. So when we go to another action and then end up at another jsp, the stuff we pushed on the value stack from the first action won't be there since the other action has it's own value stack.
reference: http://www.manning-sandbox.com/thread.jspa?messageID=93045
You guys can feel free to correct me if any of this is wrong or if there are smarter ways to do these things :).
Thanks.

Struts 2 adds your action to the top of the value stack when executed. So, the usual way to put stuff on the Value Stack is to add getters/setters for the values to your Action class. You still use the s:property tag to access the values.
A CRUD tutorial: http://struts.apache.org/2.1.6/docs/crud-demo-i.html

just define a property like
String string1 = "test string";
in your action.
in jsp you can access directly.
e.g
<s:property value="string1"/>
will print out
"test string"

Normally, as Nate says, you will use a field in your action, since the action is always on the ValueStack. However, this doesn't work if you're writing interceptor code since the interceptor will be gone by the time the template (JSP/freemarker etc) is invoked. There you need to put some kind of java bean-like object on the ValueStack, just as you do above.

Hi just for information
These is a downside of using getValueStack().getContext() sometimes the data was not available in .ftl (data was not showing in line2, but it was coming in line1) i really dont know the reason for this. But using .getValueStack().set("resDTO",resDTO); the problem was solved (data was getting populated for both the functions).
${resDTO.data} //line 1
var selonload='<#s.property value="resDTO.data" escape="false" />'; //line 2

Related

Is it possible to use an Action without a FormBean (Struts 1)?

I'm learning struts 1, yes, the old one.
Is it possible to use an Action (Dispatch Action for example) without a FormBean?
I know that is possible to use a FowardAction, but I want to use a DispatchAction because I need to use a Controller, but I don't need a FormBean, I'll get information from the query string.
Yes, you can do it like this
<action-mappings>
<action path="/myAction" name="myAction" scope="request" type="com.example.app.action.MyAction">
</action>
</action-mappings>

Testing Struts request parameter against String with odd results - why does it look like a collection?

I am calling an action via foo.action?error=bar
In struts.xml, I have configured the action chain as follows:
<action name="foo">
<interceptor-ref name="defaultStack"/>
<!-- custom interceptors -->
<result name="success">/jsp/foo.jsp</result>
</action>
In the JSP, I'm running a test:
<s:if test="#parameters.error[0] == 'bar'">
It's legacy code; this works.
However, the following does not, and I don't understand why:
<s:if test="#parameters.error == 'bar'">
Why do I need to pretend the error parameter is a collection?
Judging from the docs:
Access to ValueStack from JSPs
JSP
I shouldn't have to - but then I haven't used JSPs much...
I have added the following to the JSP, in order to help me understand what's going on:
<s:property value="#parameters.error"/> // bar
<s:property value="parameters.error"/> // <nothing>
<s:property value="parameters.error[0]"/> // <nothing>
<%= pageContext.getRequest().getParameter("error") %> // bar
<%= pageContext.getRequest().getParameter("error").getClass() %> // class java.lang.String
<s:property value="#parameters.error=='bar'"/> // false
<s:property value="'token'.getClass()"/> // <nothing>
That output confuses me even more. Can someone please explain what's going on?
You don't need to pretend, it's a collection. The new implementation uses HttpParameters and OGNL expression doesn't know that, a tag is using toString() value on object that is not a string.
You can read more about parameters in this answer.
HttpParameters. The later class implements a Map<String,Parameter>, so you can use
this to get/put parameters to the map.
Also see:
How can we access request parameters passed into an Action
How to use parameters in JSP

Intermediate redirection in struts2

i'm working with a struts2 application.
I have a form that once his is submit trigger an action :
<action name="AddDataAction" class="saisie.AddAction" method="add">
I need to create an intermediate page where the user need to log again before doing this action.
The tough thing is that I can only modify struts.xml to create that intermediate state and that after the user log in, it must execute this addDataAction method with the parameters from the form (to be save in a database).
I thought about interceptor but could they redirect to a jsp and call an action to verify the user login while conserving the data of the form to be save if the user log correctly ?
You can use result type redirectAction to achieve this.
<action name="OtherAction" class="saisie.OtherAction" method="otherMethod">
<result name="redirect" type="redirectAction">
<param name="actionName">loginAction</param>
<param name="yourParamName">${yourParamName}</param>
</result>
</action>
You can keep the parameter values by adding them to the result. Note the use of ${}. What this does is it calls the corresponding getters and adds them to the url. Then on the next page these values will be mapped to the corresponding variables using setters
You can read more about redirectAction results here

Redirecting to another action with unknown amount of parameters in Struts 2

I have a login action which after successful execution redirects to the previous page (I store the previous page in my session so I can fetch it later). In Struts2, I can find two ways to do this redirection:
<action name="login" class="com.myapp.login.Login">
<result name="redirect" type="redirect">${previousAction.requestURL}</result>
</action>
In this example, the getPreviousAction().getRequestURL() method (this is a selfmade method, its not native to Struts2) will be invoked and this will return the URL of the previous page as intended, for example:
somenamespace/index.action
There is also another type of redirection:
<action name="login" class="com.myapp.login.Login">
<result type="redirectAction">
<param name="actionName">${previousAction.name}</param>
<param name="namespace">/${previousAction.namespace}</param>
</result>
</action>
I want to use this `redirectAction result type because it is much cleaner. But, I have a problem when query parameters are part of the URL. For example:
somenamespace/index.action?name=john&age=50
I know I can add these params hardcoded in my struts.xml, but the problem is my login action should redirect to any previously invoked action, and I do not know beforehand which query parameters the previous actions had. This is different from the typical usecase where you know exactly to which action you're redirecting to
A very bad solution I found was adding every param possible (the collection of all params of all my actions in struts.xml) and then use the option:
<param name="suppressEmptyParameters">true</param>
You can save action name, namespace, and parameters from the ActionMapping.
ActionMapping mapping = ServletActionContext.getActionMapping();
You can also save query string instead of parameter map.
String params = request.getQueryString();
To add parameters dynamically to redirectAction result you should use OGNL in a dynamic parameter.
<param name="actionName">${previousAction.name +'?'+ parameters}</param>
Supposed you have a getter for parameters and initialized it from session where you saved previous query string, action name, and namespace.

hiding contents of the URL in struts

I want to hide the parameters which are attached in my url .
My action is being hit from another website (URL redirection)
https://myserver/web/myaction.do?username=jhon&password=1234
on this action I simply redirect to a jsp
<action name="myaction" class="ncom.company.project.Head">
<result>/pages/HelloWorld.jsp</result>
</action>
on my jsp username and password are visible , i want to hide them
I guess you mean the parameters should not be visible in the URL, right? If so, you should do a real redirect, what you're doing is a actually forward.
In Struts 2 you'd use the "redirect" result type to send the redirect to the browser. The parameters should still be in your session/action context.
May I suggest that you use a POST request. As far as I can see from your question you're sending a GET request. That's why you can see the parameters in the URL. I don't think this is a struts-specific problem. It's part of HTTP. Just make the other website to use a POST request.
You might wanna take a look here too to find out the usage of both methods.
You can do 2 things here either the one like redirect but in that case it means creating a new request object and a new action instance in value-stack.
I believe that once application hits the myaction and once you have done the work you can use redirectAction by passing any any parameters you need (if any).
But just be clear that even redirectAction will create a new Request Cycle you can use redirectAction like
<action name="myaction" class="ncom.company.project.Head">
<result type="redirectAction">
<param name="actionName">redirectAction</param>
// any parameter you want
</result>
</action>
<action name="redirectAction">
<result>/pages/HelloWorld.jsp</result>
</action>
here are more details for the redirectAction
Redirect Action
hope it will help you

Categories