Struts2 INPUT 结果:它是如何工作的?如何处理转换/验证错误? [英] Struts2 INPUT result: how does it work? How are conversion / validation errors handled?

查看:18
本文介绍了Struts2 INPUT 结果:它是如何工作的?如何处理转换/验证错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

主要问题

工作流程应该是这样的:如果输入的是不是数字的String,首先要通过异常拦截器,通过param拦截器的时候,转换为int类型就不行了使用 Integer.parseInt 会发生异常;不应该将该异常(即 NumberFormatException)推送到值堆栈中吗?为什么它不显示 NumberFormatException 并显示结果,即使结果不应该被打印出来?

附带问题

每当我在表单中添加一个字母时,它都会变成零...?为什么会这样?

index.jsp

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

divide.java

包动作;公共类划分{int number1,number2,result;公共字符串执行()抛出异常{结果=编号1/编号2;返回成功";}公共 int getNumber1() {返回编号1;}public void setNumber1(int number1) {this.number1 = number1;}公共 int getNumber2() {返回编号2;}public void setNumber2(int number2) {this.number2 = number2;}公共 int getResult() {返回结果;}}

result.jsp

<%@taglib uri="/struts-tags" prefix="s" %><b>除法的结果是<s:property value="result"/></b><jsp:include page="index.jsp"></jsp:include>

处理程序jsp

<%@taglib uri="/struts-tags" prefix="s"%><b>处理过程中出现以下异常<s:property value="异常"/></b><jsp:include page="index.jsp"/>

struts.xml

<!DOCTYPE 支柱公共"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"http://struts.apache.org/dtds/struts-2.0.dtd"><支柱><package name="yo" extends="struts-default"><action name="divide" class="actions.divide"><异常映射结果=错误"异常=异常"/><result name="success">/result.jsp</result><result name="error">/handler.jsp</result></动作></包></支柱>

解决方案

<块引用>

主要问题:

工作流程应该是这样的,如果一个字符串是输入的不是数字,首先它应该通过一个异常拦截器,当通过参数拦截器时,同时转换为 int 类型,使用 Integer.parseInt 将无法做到并且会发生异常,该异常是数字格式异常应该被推入值堆栈?为什么它不显示numberformatexception 并显示结果,即使结果应该不打印?

概念

Struts 2 自动处理转换错误验证错误:它不会引发异常,因为它们不是阻塞错误,但是输入错误,因此最好的方法是通知用户提交的输入是错误的,要求他提供一个新的、有效的输入.为此,将返回 INPUT 结果,而忽略 Exception.

详细工作流程

  1. 参数拦截器 尝试设置参数.如果捕获到 RuntimeException(如 NumberFormatException)并且 devModetrue,则会向 true 添加一条错误消息code>Action Errors,否则异常就被吞了.来自源代码:

    for (Map.Entry entry :acceptableParameters.entrySet()) {字符串名称 = entry.getKey();对象值 = entry.getValue();尝试 {newStack.setParameter(name, value);} catch (RuntimeException e) {如果(开发模式){String developerNotification = LocalizedTextUtil.findText(ParametersInterceptor.class, "devmode.notification", ActionContext.getContext().getLocale(), "Developer Notification:
    {0}", new Object[]{意外异常捕获设置 '" + 名称 + ' on '" + action.getClass() + :" + e.getMessage()});LOG.error(developerNotification);if (action instanceof ValidationAware) {((ValidationAware) action).addActionMessage(developerNotification);}}}}

  2. 转换错误拦截器 检查是否发生了任何转换错误:对于每个发现的错误,它添加一个Field Error;它还保存原始值,以便对该值的任何后续请求都返回原始值,而不是操作中的值.来自文档:

    <块引用>

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

  3. 验证拦截器 执行所有请求的验证(在 XML、Annotations 中定义或通过 Action 的 validate()validateXXX() 方法定义),添加一个或多个对于每个未通过一个或多个验证标准的字段,Field Errors 的错误消息.

  4. 工作流拦截器 检查是否存在 Field Errors(都来自转换错误或验证错误).如果没有发现错误,它将继续链接到下一个拦截器.如果发现一个或多个错误,则返回 INPUT 结果.

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

<!-- 其他拦截器在这里... --><interceptor-ref name="params"><param name="excludeParams">^dojo..*,^struts..*,^session..*,^request..*,^application..*,^servlet(Request|响应)..*,^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><!-- ...这里的其他拦截器-->

<块引用>

附带问题:

每当我在表单中添加一个字母时,它都会变成零...?为什么会这样?

最初的答案是:在向服务器发布请求以及检索结果页面,它调用该变量的Getter;由于您定义了 int 而不是 Integer,并且 int 不能为空,因此它将返回 int:0.

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

<块引用>

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

在类型转换期间发生的任何错误可能希望也可能不希望报告.例如,报告输入abc"无法转换为数字可能很重要.另一方面,报告空字符串"无法转换为数字可能不会重要 - 特别是在网络环境中,很难区分用户未输入值与输入空白值.

...

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

当发布abc时,这会给你0:

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

因为发生了进一步的转换错误.

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

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

结论

  • 确保拦截器堆栈配置正确,并且
  • 仔细检查您的代码(很可能不是这里发布的代码),看看您对 value 属性做了什么.

出于测试目的,首先尝试删除 value 属性,看看它是否正常工作,然后开始寻找错误.

Main Question

The work flow should be like this: if an String is entered other than a number, first it should pass through a exception interceptor, and when passing through param interceptor, while converting to int type, it wont be able to do it using Integer.parseInt and an exception would occur; shouldn't that exception (that is NumberFormatException) be pushed into Value Stack ? Why does it not show NumberFormatException and show the result even though result should not be printed instead ?

Side Question

Whenever I add an alphabet in the form, it changed to zero...? Why so ?

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>

divide.java

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>

handler 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>

解决方案

Main Question:

The work flow should be like this ,if an string is entered other than a number,first it should pass through a exception interceptor,and when passing through param interceptor,while converting to int type,it wont be able to do it using Integer.parseInt and an exception would occur,that exception that is number format exception should be pushed into value stack?so why does it not show numberformatexception and show the result even though result should not be printed instead?

Concept

Struts 2 handles both conversion errors and validation errors automatically: it does not raise an Exception, because they're not blocking errors, but input errors, hence the best way to proceed is to notify the user that the input submitted was wrong, asking him for a new, valid input. To achieve this, an INPUT result is returned, while the Exception is ignored.

Detailed worflow

  1. The Parameters Interceptor tries to set the parameters. If an RuntimeException (like NumberFormatException) is caught and devMode is true, an error message is added to the Action Errors, otherwise the exception is simply swallowed. From the source code:

    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:
    {0}", new Object[]{
                         "Unexpected Exception caught setting '" + name + "' on '" + action.getClass() + ": " + e.getMessage()
                });
                LOG.error(developerNotification);
                if (action instanceof ValidationAware) {
                    ((ValidationAware) action).addActionMessage(developerNotification);
                }
            }
        }
    }
    

  2. The Conversion Errors Interceptor checks if any conversion error happened: for each one found, it adds a Field Error; it also saves the original values such that any subsequent requests for that value return the original value rather than the value in the action. From the documentation:

    This interceptor adds any error found in the ActionContext's conversionErrors map as a field error (provided that the action implements ValidationAware). In addition, any field that contains a validation error has its original value saved such that any subsequent requests for that value return the original value rather than the value in the action. This is important because if the value "abc" is submitted and can't be converted to an int, we want to display the original string ("abc") again rather than the int value (likely 0, which would make very little sense to the user).

  3. The Validation Interceptor performs all the validation requested (defined in XML, Annotations or through the validate() or validateXXX() methods of the Action), adding one or more error messages to the Field Errors for each field not passing one or more validation criteria.

  4. The Workflow Interceptor checks if there are Field Errors (both coming from conversion errors or validation errors). If no errors are found, it continues the chain to the next Interceptor. If one or more errors are found, it returns an INPUT result.

To ensure this mechanism works, you need to define this four Interceptors in the right order in your Custom Stack, if you are not using the Default Interceptors Stack (you don't need to do anything otherwise). From 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 -->

Side Question:

Whenever I add an alphabet in the form, it changed to zero...? Why so?

The original answer was: the framework has not been able to set a String into an int field when posting the request to the server, and when retrieving the value in the resulting page, it invokes the Getter of that variable; since you defined an int and not an Integer, and an int can't be null, it will return the default value for an int: 0.

But I wasn't remembering that Conversion Interceptor claims (read point n. 2) to save the original values, to provide them in subsequent future requests, in place of the Action values (that would be null, or 0). This is also mentioned in Type Conversion Error Handling:

Type conversion error handling provides a simple way to distinguish between an input validation problem and an input type conversion problem.

Any error that occurs during type conversion may or may not wish to be reported. For example, reporting that the input "abc" could not be converted to a number might be important. On the other hand, reporting that an empty string, "", cannot be converted to a number might not be important - especially in a web environment where it is hard to distinguish between a user not entering a value vs. entering a blank value.

...

Instead, I was remembering well the behavior described in your question. So this case has already been handled... why it is not working then ? The culprit, in my case (and probably your), was the value attribute:

This will give you 0 when posting abc:

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

because a further conversion error occours.

This two cases instead work as described above, giving you abc when posting abc:

<s:textfield name = "myIntField" />

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

Conclusions

  • Ensure the Interceptor Stack is correctly configured, and
  • check carefully your code (that is most likely not the one posted here) to see what are you doing with your value attribute.

For test purposes, try removing the value attribute at all at first, to see it working the right way, then start looking for the bug.

这篇关于Struts2 INPUT 结果:它是如何工作的?如何处理转换/验证错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆