In one of my Struts action I've got the following code in a method:
...
List<Object> retrievedListOfObjects = c.getListOfObjects();
return mapping.findForward("view");
}
fw_view leads to a new Struts action with another Struts form. Let's say this form has got among others the following field
List<Object> listOfObjects;
I now want to pass the retrievedListOfObjects from within the first Struts action to the form of the following Struts action.
Is this possible without storing it in the session?
you can store it as a request attribute.
request.setAttribute("listOfObjects", listOfObjects);
and then in the Action that is forwarded to
List<Object> listOfObjects = (List<Object>)request.getAttribute("listOfObjects");
Given that when setting request attributes you can give them meaningful names, you should consider setting many attributes rather than setting one big list of objects.
Correction of krock code.
Setting object to request:
request.setAttribute("listOfObjects", listOfObjects);
Getting the object in an other action.
List<Object> listOfObjects = (List<Object>)request.getAttribute("listOfObjects");
Related
I have a scala template and I've passed a form instance with a Ticket instance populated with my data in order to render my page ticketForm : Form[Ticket]. However, part of my template renders a List<Object> items into a <ul> and I don't want to pass this list as a parameter on the template as I already have it as a property on the ticket object itself. I was using ticketForm.get().getItems but it runs the validation and throws an exception.
Is there any another way to do that?
Do not use get, just ticketForm('myproperty')
An example of generation radio group:
https://github.com/playframework/playframework/blob/master/framework/src/play/src/main/scala/views/helper/inputRadioGroup.scala.html
In the case, if you want to process a list, like the #repeat helper
#helper.repeat(userForm("emails"), min = 1) { emailField =>
#helper.inputText(emailField)
}
Here is the realization of the repeat helper:
https://github.com/playframework/playframework/blob/master/framework/src/play/src/main/scala/views/helper/Helpers.scala#L80
First let me say that using Struts2 + Freemarker is a real blast.
Yet there's something is driving me crazy, because I cannot understand why it happens. I ask here as maybe someone else has an idea to share about it.
I've got an action, with a property.
Say
private String myText;
Then I've got a setter and a getter:
public void setMyText(String myText)
{
this.myText = myText;
}
public String getMyText()
{
if (myText == null)
myText = "(empty)";
return this.myText;
}
The result (in struts.xml) is a freemarker result.
So in my Freemarker template there's a line like the following:
<p>The text is: ${myText}</p>
Now consider I'm calling the action without any text parameter: say the url is
http:localhost:8080/myapp/myaction
As the getter provides a default value, when the action is processed and the result passed to my template, the property is set to the default; so I get (html on the browser side)
<p>The text is: (empty)</p>
If I call my action with the parameter set, instead (I mean with something like:
http:localhost:8080/myapp/myaction?myText=hallo
) things go wrong. Freemarker fires the following exception:
Exception occurred during processing request: For "${...}" content:
Expected a string or something automatically convertible to string
(number, date or boolean), but this has evaluated to a
sequence+extended_hash (String[] wrapped into f.e.b.ArrayModel)
It seems that "myText" is found twice...
What am I doing wrong? Or, at least, is there anyone that can explain to me why it happens?
P.S.: it's really found twice; the following is a way to workaround the problem:
<#if myText?is_sequence>${myText[0]}<#else>${myText}</#if>
Yet it seems to me not viable to wrap every variable in that way.
P.P.S.: a further hint: in the freemarker template there's a call to another action some lines before. Something like:
<#s.action var="innerAction" name="getTable" namespace="/foo" />
If I comment the line above, everything works fine.
The myText could be a variable from the freemarker context, but if you want to use action property
<p>The text is: ${action.myText}</p>
Note, that action prefix is not required to access action properties. A property resolution method is applied when resolving freemarker variables:
Property Resoloution:
Your action properties are automatically resolved - just like in a
velocity view.
for example ${name} will result in stack.findValue("name"), which
generally results in action.getName() being executed.
A search process is used to resolve the variable, searching the
following scopes in order, until a value is found :
freemarker variables
value stack
request attributes
session attributes
servlet context attributes
And later you can read what objects are accessible from the context.
Objects in the Context:
The following variables exist in the FreeMarker views
req - the current HttpServletRequest
res - the current HttpServletResponse
stack - the current OgnlValueStack
ognl - the OgnlTool instance
This class contains useful methods to execute OGNL expressions against arbitary objects, and a method to generate a select list using
the <s:select> pattern. (i.e. taking the name of the list property, a
listKey and listValue)
struts - an instance of StrutsBeanWrapper
action - the current Struts action
exception - optional the Exception instance, if the view is a JSP exception or Servlet exception view
The error might be caused by searches from the value stack and returning something that you didn't expect depending on the structure of the stack at the moment of execution.
Adding a prefix to the variable to point out the exact location of the property should fix the redundancy in the code when searching in the value stack.
I am want to create simple form for searching records via one parameter (for example, name).
Seems like creating a class with one property (name) and than use helpers for forms - is not a best way.
Is there any examles how can I get POST data from request and fetch property value from that data?
Thanks a lot for wasting your time.
You already answered your own question, I just want to provide some more information:
You are right about creating a class with one single property, however keep in mind that you can use validation annotations (like #Required, #Email, etc.) in this class - so if there is some (super) complex logic behind this property this might also be a valuable option.
The second solution would be to use DynamicForms - you use them when you don't really have a model that is backing up the submission form. It goes like this:
public static Result index() {
DynamicForm requestData = Form.form().bindFromRequest();
String name = requestData.get("name");
return ok(name);
}
And of course the third option to get the values is like you mentioned:
String name = request().body().asFormUrlEncoded().get("name")[0];
If you do not what to use form validation, I don't think you need to create a class. Instead, you can use AJAX function like $.ajax(), that will be route to your specific controller function. Moreover, you can call your model function from your controller then at last return the result. The result will be caught by the $.ajax() function.
$.ajax
type: "POST"
url: url
data: data
success: success
dataType: dataType
I have Struts 2 actions with different (HTML and JSON ) result types. They use common interceptor.
If needed to intercept the request, how to return a result based on given action result type?
For example, my Action.ERROR forwards to JSP page. If action is JSON type I want to forward JSON error instead.
In Struts2 the action has not a type. This means that you cannot configure the type of the action. Instead you can configure result types in the xml configuration. In the xml configuration file this is defined as the result-type tag. When you configure the result using result tag you specify type attribute that will be used to determine the corresponding result type. Say name="success" or name="error" are results of the dispatcher result type.
When the action is intercepted you could get the results
Map<String, ResultConfig> results = actionInvocation.getProxy().getConfig().getResults();
In the ResultConfig there's className attribute that could be used to determine the type of the result.
I have Struts2 actions with different (HTML and JSON ) result types. They use common interceptor. If need to intercept the request, how to return result based on given action result type?
For example, my Action.ERROR forwards to JSP page. If action is JSON type I want to forward JSON error instead. Please advice.
Although is true that an Action has not a type, it's also true that, if an Action is called in an AJAX way, like an action returning JSON, all of its results should have the same result type (JSON in this case), unless you are using a single Action to perform different logical actions (ajax and non-ajax operations, that is an anti-pattern);
That said, if you want to return the proper GLOBAL error result, from inside an Interceptor that is used by all of your Actions (each one with its result type), based on their other result type (let's say: SUCCESS, assuming every Action has a SUCCESS result), this is the way to do it:
public String intercept(ActionInvocation invocation) throws Exception {
// Get the action configuration defined in struts.xml
ActionConfig config = invocation.getProxy().getConfig();
// Get the SUCCESS result configured for that Action
ResultConfig success = config.getResults().get("success");
// Get the class of the SUCCESS result
Object clazz = success.getClass();
/* .... oops, some error occurred !!
We now need to redirect to the right global error result .... */
if (clazz instanceof org.apache.struts2.dispatcher.ServletDispatcherResult) {
log.debug("Struts2 Result type: CLASSIC");
return "error";
} else if (clazz instanceof org.apache.struts2.json.JSONResult) {
log.debug("Struts2 Result type: JSON");
return "jsonError";
} else {
log.debug("Struts2 Result type: SOMETHING ELSE, returning default ");
return "error";
}
}
Although this is technically possible, i would discourage it because... there is no real reason to do it;
For your purpose, remember that each global result is scoped in its <package>;
Since you could (/should) have two different packages for Classic Actions (a <package> extending struts-default) and JSON Actions (a <package> extending json-default), you can simply define two different global error result for each package with the same name but different result type; this way the Interceptor will call the one relative to the package of the current Action, outputting the desired kind of result.
I am creating a wizard-like interface consisting of 3 jsp pages and 3 Struts actions using Struts 1.3. The flow is like below:
page1>action1 ->page2>action2 -> page3>action3
I use a session form bean (an action form with session scope) to share data between requests. The problem I am having is that the data I submitted in page2 is available in action 2, but not in action 3. I am in doubt it might be I don't have a form on page3 to hold those data, or because I call action3 via jQuery post method instead of a regular form submit, but I am really not sure.
I have been digging all the internet for almost a day and still no luck. Could anyone offer some help. Thanks a lot.
The reset() method on the form is being called with each request and thus you are losing state. You can programmatically control this.
public class MyForm extends ActionForm {
boolean reset = true;
private String[] checkboxes = {};
#Override
public void reset(ActionMapping mapping, HttpServletRequest request) {
if (reset) {
this.checkboxes = new String[];
// etc
}
reset = true;
}
public void doNotReset() {
reset = false;
}
}
Have action2 call doNotReset() on the form.
I suppose that you might have assigned a same form to both the action in StrutsConfig.xml and hence it is not giving the ClassCastException. By the way, if you want to access the same form bean which was filled on action 2 stuff, do the following
Look at the strutsConfig file for actionMapping of both the actions (2 and 3). keep the name of form different for separate action (e.g. form2 for action2 and form3 for action3).
In Action3, instead of casting the form, use this form2 = (FormBean2) session.getAttribute("form2");
The reason for above is since both the actions are using the same form, struts might have overwriting it. Hopefully above will solve your problem.
Thank you for all your inputs. Here is how I solved my problem. I don't really like this solution, but it possibly the neatest one I can find.
In page 3 I added hidden fields for what ever property I want to be available in action 3. Struts will store the values in those hidden field and when the form is submitted again, the data will then re-populated to the action form.
It seems to me that Struts works like this: when it loads page 3, it try to populate the form in page 3 with values of myForm. When the form is submitted, the process is reversed, it populate myForm with values from the user's form. The problem is that, before populating myForm with values submitted by user, it resets myForm's properties. And because after reseting, it doesn't find the value for those fields, it leaves it empty.
I don't think it makes sense for Struts to work that way, but... so be it.
How are you accessing the form bean of page2 in action2 as well as in action3.
I suppose you are accessing the wrong way. Are you getting an exception regarding invalidCast or something.