As I understand it, Struts2 action class instances can (unlike Struts1) be stateful, because each GET or POST to an action creates a new instance of the backing action class.
I also see that there's a standard(?) idiom (Pattern?) to provide input forms: the same .jsp is used as the View component of two different actions, like this:
<action name="showForm" class="defaultActionThatDoesNothingExceptReturnSuccess">
<result name="success">inputForm.jsp</result>
</action>
<action name="validateAndProcessForm" class="realAction">
<result name="input">inputForm.jsp</result>
<result name="success">formProcessed.jsp</result>
</action>
The first action just displays the form, without validating the input or processing it. The form in the .jsp posts to the second action:
<s:form action="validateAndProcessForm" method="post">
and that second action validates the posted fields/parameters, returning "input" if the form's inputs are incomplete or invalid, or actually calling the action class's execute if the inputs are complete and valid, thus processing the form and returning the (e.g.) formProcessed.jsp that displays something like "thanks for your input!".
So we have this sort of "picket fence" idiom:
defaultAction- -> realAction-
| | | |
-> input.jsp- <--- -> success.jsp
This is done so that the first time input.jsp is displayed, validations aren't called (and so validation errors are not shown), but that after the submit button on that jsp is clicked, the "real" action will validate the input, possibly passing back errors calling out invalid input which the input.jsp will display.
Which brings us back to stateful, non-singleton actions; because the action is stateful and thus not shared across GETs or POSTs, and each instance is instantiated just for that GET or POST, the action has no way to know if a particular session has "GETted" the same page multiple times. So GETting showForm.action will never validate, and GETing validateAndProcessForm will always validate (and show errors if the parameters are invalid), even if that GET is the first time a particular session has "GETted" that URL.
Which is why we need the "fence post": the first action just to display the form, the second to capture the input.
Is my understanding correct? Is there a less verbose way to do this, to not validate input on the initial GET, but to validate on the POST, without having to have two actions for every form?
There is another way to perform what you want without the picket fence. The validation interceptor, by default, does not fire for the input method. You can therefore update your struts.xml to the following:
<action name="*MyForm" method="{1}" class="realAction">
<result name="input">inputForm.jsp</result>
<result name="success">formProcessed.jsp</result>
</action>
With this setup, you do not need the empty action at all. When you first go to the form, you would go to the url "inputMyForm", and have your form action just point to "MyForm". The {1} in the method block just means that the framework will call whatever method matches the * from the action name. If the * match is empty, it defaults to the execute method. So you get the following kinds of actions:
inputMyForm would go to the input() method of your action class
MyForm would go to the execute() method of your action class
executeMyForm would go to the execute() method of your action class
customMethodNameMyForm would go to the customMethodName() method of your action class
Since the validator interceptor excludes any actions going to the input method, you can set up whatever validation you want for this action, and it will only look for it when you submit the form. Since every time you submit the form, it is going to the execute method, the validation will occur every time you submit the form.
Also, if you are extending the ActionSupport class, that class already defines the input() method, so you would not even need to change your action class to accomplish this.
It's possible to do things differently but lets say you let struts2 handle all the requests. Everything that struts2 handles is an "action".
Don't worry about GET or POST they are just two different methods of sending data to an action, if there are parameters (regardless if they are get or set) then struts2 will try to place that data onto the actions class (assuming there is one). If there is a validation method (or a properly named validation xml file) then validation will be run after the class properties are set. Then the execute() method for the class is called (assuming there is a class). After this a jsp is typically rendered which has at its disposal all the public data in the action's method.
Take your "showForm" action... you can reduce the xml to:
<action name="showForm">
<result>inputForm.jsp</result>
</action>
You can see you don't need to define a class. Further the default result is success so we don't need to mention that either.
So when thinking of hmtl we would think in terms of pages. When thinking in struts we think in terms of actions, they only need to be as complicated as necessary. That is if you need to show a form then you need a show form action, if you want a display page that uses the form data then you need a "displayPage" action which does something with the form data.
So think of each action as starting with a url > ----------- > ending with returning date (generally rendering a jsp). The dashes are the optional parts that you may define, but if you don't they will sensibly default for you. To see what features are provided to you you'll need to look in struts2-core-x.x.x.x.jar and view the contents of the struts-default.xml that is where "defaultStack" is defined. Each interceptor in turn is called, knowing what they offer (and the other interceptors offer) let you know what you get out of the box (I wouldn't look into them too deeply just know they are there so you'll know for instance that if you need to upload a file the simple fact that the "fileUpload" intercepter is in the default stack should be indication enough that there must be built in file uploading capabilities.
So no there is not a "false action" to the input form. It is a real action abet a simple one. After you learn how to define packages, actions, default actions for a package and perhaps globally and learn how to define an interceptor then you should look at the conventions plug in. It makes life a lot easier!
Your question makes sense. Your pattern is correct, though:
as Quaternion pointed out, there is little or no "verbosity". Your first "showForm" is a dummy "action mapping", its "do nothing" class does not need a particular class definition (the default ActionSupport is enough).
there are other possible patterns; some people might prefer the idiom you are pointing out (and it has a long history - I remember doing some pelr CGI pages in that way, centuries ago) : use a single url (and hence a single action mapping) for the two "steps" (show the initial form and process the form), by guessing inside the action method (or in the validator) the current step, perhaps by checking that some parameter is present (perhaps a hidden field) or perhaps by discriminating POST/GET. In Struts2, I prefer the other way, in general.
BTW, calling the Struts2 actions "stateful" is correct only if you undestand (you do, apparently) that that 'state' does not survive among requests.
Related
I have a Spring Portlet application and the landing page of an application is a data entry form which is annotated by RenderMapping.
Is there a method that I can override which is executed before the RenderMapping method is called? My requirement is to clear Session attributes using SessionStatus.setComplete() and I wanted to do that(if possible) in the first method. When I did that in the RenderMapping method, the Model attributes became empty and when I tried to submit, I got an error which said Model Attribute is empty or something like that.
The reason I wanted to call SessionAttribute.setComplete() is to clear all SessionAttributes used, so that I get clear form.
Also is there a way to forward or redirect from one RenderMapping method to another RenderMapping method? Didn't see a way when looked, but still wondering.
Any ideas to handle this?
I ran into this issue: our SpringMVC Validator validates a form (the normal case); this works OK.
Also, in a separate use case, it needs to be called remotely from a different location to put an exclamation point icon ("!") in front of some element on a different screen that refers to that form object.
I can validate any object of the class supported by the Validator, but the issue is how to add errors:
1) On the one hand, this Validator should reject errors for the path on its screen when it's used in the normal case:
errors.rejectValue("object.field.path", "errorCode", args, defaultMessage);
2) On the other hand, this will fail when it's called remotely, this path doesn't exist because the form is different. The only thing I can do here is something that doesn't depend on paths,
errors.rejectValue("errorCode");
Ideally the same Validator should respond to both cases... It should tell me there are validation errors on the form. In Case A it's specific, in Case B it's general. Can anyone advise how to approach this?
UPDATE The issue is general Bean Validation vs. GUI Validation. I understand is that SpringMVC's Validators are strongly tied to the GUI. But we also need a generic way to validate data beans, and hopefully reuse that. Or maybe I can create a "mock" BindingResult/JSP?
Since there seem to be no methods for input validation in JavaFX, I was thinking about how to do it in a clean way in my current project.
Here is my idea:
All validation rules are regular expressions (like "min-length", "not-empty", "only-numbers", etc), which are stored in a .properties file
Example: validationrules_only_numbers="[0-9]+"
I use this validations in the .fxml file by defining the <properties> tag for any input that should be validated
Example:
<ChoiceBox><properties rules="%validationrules_only_numbers"/></ChoiceBox>
In an abstract/parent controller I write a method which gets all children of the current AnchorPane and iterates over them (lets say after the user clicks OK to submit the form). All children which have validation rules are them passed to another method, which depending on the Type of the inputfield applies the validation rules to the input.
All controls with validation errors then get highlighted.
What I personally like about this idea:
the validation rules are easily expandable by just adding them to the .properties file
the rules are assigned in the .fxml file
all the controllers (which extend the abstract/parent controller) dont need to perform any validation tasks
What I dont like/am unsure if it works good in reality:
the validation rules are all regular expressions, I don't know if that works well with all the input fields (but I don't mind coding "hacks" to make it work, since I would do it only one time in a parent controller)
I must check the controls with instanceof to apply the rule correctly for this specific control, since not all controls have a getText() method and the input needs to be validated in other ways
don't know if there is a better way to put the rules in the .fxml file then using <properties>
What are your thoughts? Is there anything important I am missing here?
I was googling about this topic for several days and there seems to be no really good solution like those we are familiar with from the web development community.
Before you re-invent the wheel you might want to have a look at the validation framework contained in the ControlsFX package. Maybe you can combine that with your ideas.
I'm designing an application trying to follow the REST spec. I'm trying to figure out the best way to design it.
So let's say I'm doing a POST call that so I have a "post" method in my controller and model
// in controller
function post()
{
//call post model here
}
In my post request I need to make the following checks:
-validate fields
-make sure item name is unique for that user
-make sure there are less than 10 items
-etc (there could be more cases)
Now in controller post function I will return a REST message and status code based on whatever happens, which is fine, but I'm curious to know where it's better to keep all those checks.
I can put all the checks in the model and then return some kind of array like:
array('text' => 'return response text/array or whatever here', 'code' => '200/400/etc')
Then just return this in the controller, or is it better to break up those checks into individual functions within the model and then do all the checks in the controller?
// in controller
function post()
{
//if validation fails -> send response
//if name is not unique -> send response
//etc...
}
From a design point of view, if I ever wanted to potentially call the "post" method in the project model from other methods, it would not have an all encompassing function to handle it, however if I do keep it all in one model function it doesn't give me a lot of reusability. If I had to pick sides, chances are I probably wouldn't need to reuse those "check functions" too much anyway, however it also seems weird to have all that response info in the model rather than the controller.
Can anyone please give me some input on this.
I would not create post method inside the model (although having it in the controller is perfectly fine) simply because you just put code/model in such a frame that is not re-usable plus less readable. For instance, instead of post method in the model I would create create method.
There is no one-fits-all way for data validation. I like creating validation classes which have only one method validate for various data types (e.g. username validation class checks if it matches regex and is unique). It's better than copy pasting the validation code to every action (DRY). Where to call this class method? It depends. You can simply call that it in the action. Since the validation code is inside the validation class, it will look alright. You can also create a mapper which takes the request, determines what validations have to be performed and etc. but it might be overkill and is hard to do properly (maintainability wise).
For output again - DRY. It depends on what MVC framework are you using and there might be a good solution for this already. If not, you can create a class for that (yup, I am DRY maniac). You pass response code, array (or string) with response and class nicely wraps everything into JSON, XML format. Advantages: if you change then output format then you need to change only in one place.
Also consider using Remote Facade pattern.
Hopefully, you found something useful in this post.
I would separate the API from the MVC application and use Apify
I have a model object that has a collection of children in a header-detail relationship, with the header handled in one action class (and form) and the details edited in a separate action class (and form). I want to be able to do a full validation of the whole graph of objects from the header when I save the header object; I've already declared a visitor as such inside the header's -validation.xml: (we're using XML validation in this project)
<field name="details">
<field-validator type="visitor" />
</field>
The detail class also has the proper validation.
We happen to also create/prepopulate this particular object graph from another graph; however, the prepopulation will leave some e.g. required fields as empty.
What happens is that only the header gets validated, since that's the form being submitted when the save method runs. Is it possible to force validation of the details as well (via the visitor I declared), when in fact the details don't have any form elements in the header form?
I want to keep it DRY and not have to do explicit validation inside the header action's validate() method.
Part of the problem is that when the validation runs, struts only sees the object as it was created from the form. If the list of details are not referenced in the form in some way, the xml validation won't be able to see that information in order to validate it.
One possible solution would be to include the detail information in the form through hidden fields. You could iterate over the list, and add a hidden field for each detail object. You would probably need some kind of custom data converter, unless you wanted a hidden field for each data member of the detail object.
Other than that, I can't see any way to do it solely through xml validation.