帮助我更好地理解 Struts2、验证和有状态操作
据我了解,Struts2 操作类实例(与 Struts1 不同)可以是有状态的,因为对操作的每个 GET 或 POST 都会创建支持操作类的新实例。
我还看到有一个标准(?)惯用法(模式?)来提供输入表单:相同的 .jsp 用作两个不同操作的视图组件,如下所示:
<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>
第一个操作仅显示表单,而不验证输入或对其进行处理。 .jsp 中的表单发布到 第二 操作:
<s:form action="validateAndProcessForm" method="post">
第二个操作验证发布的字段/参数,如果表单的输入不完整或无效,则返回“输入”,或者实际调用操作类的 <如果输入完整且有效,则执行 code>execute,从而处理表单并返回(例如)formProcessed.jsp
,其中显示类似“感谢您的输入!”。
所以我们有这种“尖桩篱笆”习惯用法:
defaultAction- -> realAction-
| | | |
-> input.jsp- <--- -> success.jsp
这样做是为了第一次显示 input.jsp
时,不会调用验证(因此不会显示验证错误),但是单击该 jsp 上的提交按钮后,“真实”操作将验证输入,可能会传回错误,调用 input.jsp
将显示的无效输入。
这让我们回到有状态的、非单例的操作;因为该操作是有状态的,因此不会在 GET 或 POST 之间共享,并且每个实例都是针对该 GET 或 POST 实例化的,所以该操作无法知道特定会话是否多次“GET”同一页面。因此,GETting showForm.action
将从不验证,而 GETing validateAndProcessForm
将始终验证(如果参数无效),即使该 GET 是特定会话第一次“GETted”该 URL。
这就是为什么我们需要“栅栏柱”:第一个操作只是为了显示表单,第二个操作是为了捕获输入。
我的理解正确吗?是否有一种不太冗长的方法来做到这一点,不验证初始 GET 上的输入,而是验证 POST 上的输入,而不必为每个表单执行两个操作?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
还有另一种方法可以在没有尖桩篱笆的情况下执行您想要的操作。默认情况下,验证拦截器不会针对输入法触发。因此,您可以将 struts.xml 更新为以下内容:
通过此设置,您根本不需要空操作。当您第一次访问表单时,您将访问 url“inputMyForm”,并且让表单操作指向“MyForm”。方法块中的 {1} 仅表示框架将调用与操作名称中的 * 匹配的任何方法。如果*匹配为空,则默认为execute方法。因此,您将获得以下类型的操作:
由于验证器拦截器排除任何进入输入法的操作,因此您可以为此操作设置所需的任何验证,并且它只会在您提交表单时查找它。由于每次提交表单时,都会进入执行方法,因此每次提交表单时都会进行验证。
另外,如果您要扩展 ActionSupport 类,该类已经定义了 input() 方法,因此您甚至不需要更改操作类来完成此操作。
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:
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:
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.
可以采取不同的做法,但假设您让 struts2 处理所有请求。 struts2处理的一切都是“动作”。
不要担心 GET 或 POST,它们只是将数据发送到操作的两种不同方法,如果有参数(无论它们是获取还是设置),那么 struts2 将尝试将该数据放置到操作类中(假设有一)。如果存在验证方法(或正确命名的验证 xml 文件),则将在设置类属性后运行验证。然后调用该类的execute()方法(假设有一个类)。此后,通常会呈现一个 jsp,它可以处理操作方法中的所有公共数据。
执行“showForm”操作...您可以将 xml 缩减为:
您可以看到不需要定义类。此外,默认结果是成功,因此我们也不需要提及这一点。
因此,当考虑 hmtl 时,我们会考虑页面。当我们用 Struts 思考时,我们会根据动作来思考,它们只需要像必要的那样复杂即可。也就是说,如果您需要显示表单,那么您需要一个显示表单操作,如果您想要一个使用表单数据的显示页面,那么您需要一个“displayPage”操作来对表单数据执行某些操作。
因此,请将每个操作视为以 url > 开头。 ----------->以返回日期结束(通常呈现一个jsp)。破折号是您可以定义的可选部分,但如果您不这样做,它们将明智地为您默认。要查看为您提供了哪些功能,您需要查看 struts2-core-xxxxjar 并查看定义“defaultStack”的 struts-default.xml 的内容。每个拦截器依次被调用,知道它们提供什么(以及其他拦截器提供),让您知道开箱即用的内容(我不会太深入地研究它们,只是知道它们在那里,所以您会知道例如如果您需要上传文件,“fileUpload”拦截器位于默认堆栈中的简单事实应该足以表明必须内置文件上传功能,
因此输入表单不存在“错误操作” 。这是一个简单的实际操作,在您学习如何定义包、操作、包的默认操作(也许是全局的)并学习如何定义拦截器之后,您应该查看约定插件。容易多了!
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:
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!
你的问题有道理。不过,您的模式是正确的:
正如四元数所指出的,很少或根本没有“冗长”。你的第一个“showForm”是一个虚拟的“动作映射”,它的“什么都不做”类不需要特定的类定义(默认的 ActionSupport 就足够了)。
还有其他可能的模式;有些人可能更喜欢你指出的习惯用法(它有很长的历史 - 我记得几个世纪前就以这种方式做了一些 pelr CGI 页面):对两个“步骤”使用单个 url(因此是单个操作映射) “(显示初始表单并处理表单),通过猜测操作方法内部(或在验证器中)当前步骤,也许通过检查某些参数是否存在(可能是隐藏字段),或者也许通过区分 POST/GET。在 Struts2 中,一般来说我更喜欢另一种方式。
顺便说一句,只有当您了解(显然您确实了解)该“状态”在请求中无法保留时,将 Struts2 操作称为“有状态”才是正确的。
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.