帮助我更好地理解 Struts2、验证和有状态操作

Posted

技术标签:

【中文标题】帮助我更好地理解 Struts2、验证和有状态操作【英文标题】:Help me better understand Struts2, validation, and stateful actions 【发布时间】:2011-01-13 03:07:48 【问题描述】:

据我了解,Struts2 动作类实例可以(与 Struts1 不同)是有状态的,因为对动作的每个 GET 或 POST 都会创建一个支持动作类的新实例。

我还看到有一个标准(?)习语(模式?)来提供输入表单:相同的 .jsp 用作两个不同操作的 View 组件,如下所示:

<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 中的表单发布到 second 操作:

<s:form action="validateAndProcessForm" method="post">

并且第二个操作验证发布的字段/参数,如果表单的输入不完整或无效,则返回“输入”,或者如果输入完整且有效,则实际调用操作类的execute,从而处理表单并返回(例如formProcessed.jsp 显示类似“感谢您的输入!”。

所以我们有这种“栅栏”成语:

defaultAction-           -> realAction-
             |           |     |       |
             -> input.jsp-  <---       -> success.jsp

这样做是为了在第一次显示 input.jsp 时不会调用验证(因此不会显示验证错误),但是在单击该 jsp 上的提交按钮后,“真实”操作将验证输入,可能会传回错误,指出input.jsp 将显示的无效输入。

这让我们回到了有状态的、非单例的动作;因为该操作是有状态的,因此不会在 GET 或 POST 之间共享,并且每个实例仅针对该 GET 或 POST 进行实例化,因此该操作无法知道特定会话是否已多次“获取”同一页面。所以 GETing showForm.action永远验证,而 GETing validateAndProcessForm总是验证(如果参数无效则显示错误),即使 GET 是特定会话第一次“获取”该 URL。

这就是我们需要“栅栏柱”的原因:第一个动作只是显示表单,第二个动作是捕获输入。

我的理解正确吗?有没有更简洁的方法来做到这一点,不在初始 GET 上验证输入,而是在 POST 上验证,而不必为每个表单执行两个操作?

【问题讨论】:

不要使用单独的操作来查看表单和处理表单。 【参考方案1】:

还有另一种方法可以在没有栅栏的情况下执行您想要的操作。默认情况下,验证拦截器不会为输入法触发。因此,您可以将 struts.xml 更新为以下内容:

<action name="*MyForm" method="1" class="realAction">
  <result name="input">inputForm.jsp</result>
  <result name="success">formProcessed.jsp</result>
</action>

使用此设置,您根本不需要空操作。当您第一次访问表单时,您将访问 URL“inputMyForm”,并让您的表单操作指向“MyForm”。方法块中的 1 仅表示框架将调用与操作名称中的 * 匹配的任何方法。如果 * 匹配为空,则默认为执行方法。所以你会得到以下几种动作:

inputMyForm 将转到您的操作类的 input() 方法 MyForm 将转到您的操作类的 execute() 方法 executeMyForm 将转到您的操作类的 execute() 方法 customMethodNameMyForm 将转到您的操作类的 customMethodName() 方法

由于验证器拦截器排除了任何进入输入法的动作,你可以为这个动作设置任何你想要的验证,它只会在你提交表单时寻找它。由于每次提交表单都会去execute方法,所以每次提交表单都会进行验证。

此外,如果您正在扩展 ActionSupport 类,该类已经定义了 input() 方法,因此您甚至不需要更改您的操作类来完成此操作。

【讨论】:

【参考方案2】:

可以做不同的事情,但假设您让 struts2 处理所有请求。 struts2 处理的一切都是“动作”。

不要担心 GET 或 POST 它们只是将数据发送到动作的两种不同方法,如果有参数(无论它们是获取还是设置),那么 struts2 将尝试将该数据放入动作类(假设有一个)。如果存在验证方法(或正确命名的验证 xml 文件),则验证将在设置类属性后运行。然后调用该类的 execute() 方法(假设有一个类)。在此之后,通常会呈现一个 jsp,它拥有操作方法中的所有公共数据。

采取“showForm”行动...您可以将 xml 缩减为:

<action name="showForm">
  <result>inputForm.jsp</result>
</action>

你可以看到你不需要定义一个类。此外,默认结果是成功,所以我们也不需要提及。

所以在考虑 hmtl 时,我们会考虑页面。当我们在 struts 中思考时,我们根据动作来思考,它们只需要尽可能复杂。也就是说,如果你需要显示一个表单,那么你需要一个显示表单动作,如果你想要一个使用表单数据的显示页面,那么你需要一个“显示页面”动作来处理表单数据。

因此,将每个操作视为以 url 开头 > ----------- > 以返回日期结尾(通常呈现 jsp)。破折号是您可以定义的可选部分,但如果您不这样做,它们将明智地默认为您。要查看提供给您的功能,您需要查看 struts2-core-x.x.x.x.jar 并查看定义“defaultStack”的 struts-default.xml 的内容。依次调用每个拦截器,知道它们提供的内容(以及其他拦截器提供的内容)让您知道开箱即用的内容(我不会深入研究它们,只是知道它们在那里,所以您会知道例如如果您需要上传文件,“fileUpload”拦截器在默认堆栈中的简单事实应该足以表明必须内置文件上传功能。

因此,输入表单不存在“错误操作”。这是一个真正的行动,教唆一个简单的行动。在您了解如何定义包、操作、包的默认操作以及可能是全局的并了解如何定义拦截器之后,您应该查看约定插件。它让生活变得更轻松!

【讨论】:

【参考方案3】:

你的问题很有道理。不过,您的模式是正确的:

正如四元数指出的那样,几乎没有“冗长”。您的第一个“showForm”是一个虚拟的“动作映射”,它的“什么都不做”类不需要特定的类定义(默认的 ActionSupport 就足够了)。

还有其他可能的模式;有些人可能更喜欢您指出的习语(它有很长的历史 - 我记得几个世纪前以这种方式做过一些 pelr CGI 页面):对两个“步骤”使用单个 url(因此单个动作映射) "(显示初始表单并处理表单),通过在操作方法(或验证器)内部猜测当前步骤,可能通过检查某些参数是否存在(可能是隐藏字段)或通过区分 POST/GET。在 Struts2 中,我一般更喜欢另一种方式。

顺便说一句,仅当您不理解(显然您确实如此)该“状态”在请求中不存在时,才将 Struts2 操作称为“有状态”是正确的。

【讨论】:

是的,有状态的,不是持久的。

以上是关于帮助我更好地理解 Struts2、验证和有状态操作的主要内容,如果未能解决你的问题,请参考以下文章

有人可以帮助我更好地理解 Room 持久性库吗?

无状态身份验证和有状态身份验证

我没有完全得到“存在”的部分。谁能帮助我更好地理解它? [关闭]

有人可以帮助我更好地理解正则表达式中的零或一,并可能在同一个正则表达式语句中嵌套另一个

用于无头和有头的 Webdriverio 的基本身份验证

更好地理解 javascript 预编译