Percy

Struts2 INPUT结果:如何工作?如何处理转换/验证错误?

java

主要问题

工作流程应如下:如果输入的字符串不是数字,则首先应通过异常拦截器,当通过参数拦截器时,转换为int类型时,将无法使用Integer.parseInt和来完成此操作。将会发生异常;难道不应该将该异常(即NumberFormatException)推入Value Stack吗?为什么NumberFormatException即使不打印结果也不能显示结果呢?

附带问题

每当我在表格中添加一个字母时,它就会变为零…?为什么这样 ?

index.jsp

<%@ taglib uri="/struts-tags" prefix="s"%>
<s:form action="divide">
    <s:textfield name="number1" label="number1"/>
    <s:textfield name="number2" label="number2"/>
    <s:submit value="divide"/>
</s:form>

除法

package actions;

public class divide {
    int number1,number2,result;
    public String execute() throws Exception
    {
        result=number1/number2;
        return "success";
    }
    public int getNumber1() {
        return number1;
    }
    public void setNumber1(int number1) {
        this.number1 = number1;
    }
    public int getNumber2() {
        return number2;
    }
    public void setNumber2(int number2) {
        this.number2 = number2;
    }
    public int getResult() {
        return result;
    }


}

result.jsp

<%@taglib uri="/struts-tags" prefix="s" %>
<b>
    the result of division is
    <s:property value="result"/>
</b>
<jsp:include page="index.jsp"></jsp:include>

处理程序jsp

<%@taglib uri="/struts-tags" prefix="s"%>
<b>
    following exception occured during the processing
    <s:property value="exception"/>
</b>
<jsp:include page="index.jsp"/>

struts.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC 
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">
    <struts>
        <package name="yo" extends="struts-default">
            <action name="divide" class="actions.divide">
                <exception-mapping result="error" exception="Exception"/>
                <result name="success">/result.jsp</result>
                <result name="error">/handler.jsp</result>
            </action>
        </package>
    </struts>

阅读 276

收藏
2020-12-04

共1个答案

一尘不染

主要问题:

工作流程应该是这样的,如果输入的字符串不是数字,则首先应通过异常拦截器,然后在通过参数拦截器转换为int类型时将无法使用Integer进行操作。 parseInt并发生异常,该异常(即数字格式异常)应被推入值堆栈?为什么即使不打印结果,它也不显示numberformatexception并显示结果?

概念

Struts 2自动处理转换错误和验证错误:它不会引发异常,因为它们不会阻止错误,但是会输入错误,因此最好的处理方法是通知用户输入的错误,问他获得新的有效输入。为此,返回一个INPUT结果,而忽略Exception。

详细的工作流程

  1. Parameters Interceptor试图设置的参数。如果RuntimeException(和NumberFormatException)被捕获并devModetrue,则会向中添加一条错误消息Action Errors,否则将吞下该异常。从源代码:
for (Map.Entry<String, Object> entry : acceptableParameters.entrySet()) {
    String name = entry.getKey();
    Object value = entry.getValue();
    try {
        newStack.setParameter(name, value);
    } catch (RuntimeException e) {
        if (devMode) {
            String developerNotification = LocalizedTextUtil.findText(ParametersInterceptor.class, "devmode.notification", ActionContext.getContext().getLocale(), "Developer Notification:\n{0}", new Object[]{
                     "Unexpected Exception caught setting '" + name + "' on '" + action.getClass() + ": " + e.getMessage()
            });
            LOG.error(developerNotification);
            if (action instanceof ValidationAware) {
                ((ValidationAware) action).addActionMessage(developerNotification);
            }
        }
    }
}
  1. 在Conversion Errors Interceptor为每一个找到,它增加了一个:如果任何转换误差发生的检查Field Error; 它还保存原始值,以便对该值的任何后续请求都返回原始值,而不是操作中的值。从文档中:

此拦截器会将在ActionContext的conversionErrors映射中找到的任何错误添加为字段错误(前提是该操作实现了ValidationAware)。此外,任何包含验证错误的字段都将保存其原始值,以便对该值的任何后续请求都将返回原始值,而不是操作中的值。这很重要,因为如果提交了值“ abc”并且无法将其转换为int,我们希望再次显示原始字符串(“ abc”),而不是int值(可能为0,这几乎没有意义)给用户)。

在Validation Interceptor所有的验证请求的执行(在XML,注解或通过定义的validate()或validateXXX()行动的方法),将一个或多个错误消息到Field Errors每个字段不通过一个或多个验证标准。

  1. 该Workflow Interceptor检查是否存在Field Errors(无论是从转换错误或验证错误来)。如果未发现错误,它将继续链接到下一个拦截器。如果发现一个或多个错误,则返回INPUT结果。

为了确保此机制正常工作,如果您不使用默认拦截器堆栈,则需要在自定义堆栈中按正确的顺序定义这四个拦截器(您无需执行其他任何操作)。来自struts-default.xml:

<!-- others interceptors here... -->
<interceptor-ref name="params">
    <param name="excludeParams">^dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,^parameters\..*,^action:.*,^method:.*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
    <param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
    <param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<!-- ... others interceptors here -->

附带问题:
每当我在表格中添加一个字母时,它就会变为零…?为什么这样?

最初的答案是:在将请求发布到服务器时,框架无法将a设置String为int字段,并且在结果页中检索值时,框架将调用该变量的Getter。由于您定义了anint和not Integer,并且anint不能为null,因此它将返回an的默认值int:0。

但是我不记得转换拦截器声称(读取点n.2)保存原始值,以便在以后的后续请求中提供它们来代替Action值(该值为null或0)。类型转换错误处理中也提到了这一点:

类型转换错误处理提供了一种区分输入验证问题和输入类型转换问题的简单方法。

在类型转换期间发生的任何错误可能会或可能不会希望被报告。例如,报告输入的“ abc”无法转换为数字可能很重要。另一方面,报告一个空字符串“”不能转换为数字可能并不重要-尤其是在网络环境中,很难区分用户没有输入值还是输入空白值。

相反,我很好地记住了您的问题中描述的行为。所以这个案子已经处理了……为什么不起作用呢?在我(可能是您)的情况下,罪魁祸首是以下value属性:

这将0在发布时给您abc:

<s:textfield name = "myIntField" 
            value = "%{getText('format.number',{myIntField})}" />

因为会发生进一步的转换错误。

相反,这两种情况均如上所述工作,abc在发布时为您提供abc:

<s:textfield name = "myIntField" />

<s:textfield name = "myIntField" 
            value = "%{myIntField}" />

结论
确保拦截器堆栈已正确配置,并且
仔细检查您的代码(很可能不是此处发布的代码),以查看您对value属性的处理方式。
出于测试目的,请尝试首先删除该value属性,以使其以正确的方式工作,然后开始查找错误。

2020-12-04