Результат Struts2 INPUT: как это работает? Как обрабатываются ошибки преобразования / проверки?

Главный вопрос

Рабочий процесс должен выглядеть следующим образом: если строка вводится не числом, сначала она должна проходить через перехватчик исключений, а при прохождении через перехватчик param при преобразовании в тип int она не сможет сделать это с помощью Integer.parseInt и возникнет исключение; не должно это исключение (то есть NumberFormatException) быть вставленным в стек значений? Почему это не показывает 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>

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>

обработчик 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>

1 ответ

Решение

Главный вопрос:

Рабочий процесс должен выглядеть следующим образом: если строка вводится не числом, сначала она должна проходить через перехватчик исключений, а когда она проходит через перехватчик param, при преобразовании в тип int она не сможет сделать это с помощью Integer. parseInt и возникнет исключение, это исключение, то есть исключение формата числа, должно быть помещено в стек значений? так почему же оно не показывает numberformatexception и не показывает результат, даже если вместо этого результат не должен быть напечатан?

концепция

Struts 2 автоматически обрабатывает как ошибки преобразования, так и ошибки проверки: это не вызывает исключения, потому что они не блокируют ошибки, а вводят ошибки, поэтому лучший способ продолжить - уведомить пользователя о том, что введенный ввод был неправильным, и спросить его для нового, действительного ввода. Для этого возвращается результат INPUT, а исключение игнорируется.

Подробный рабочий процесс

  1. Parameters Interceptor пытается установить параметры. Если RuntimeException (лайк NumberFormatException) пойман и devMode является true сообщение об ошибке добавляется к 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);
                }
            }
        }
    }
    
  2. Conversion Errors Interceptor проверяет, произошла ли какая-либо ошибка преобразования: для каждого найденного она добавляет Field Error; он также сохраняет исходные значения, так что любые последующие запросы для этого значения возвращают исходное значение, а не значение в действии. Из документации:

    Этот перехватчик добавляет любую ошибку, обнаруженную в карте ConversionErrors в ActionContext, как ошибку поля (при условии, что действие реализует ValidationAware). Кроме того, любое поле, содержащее ошибку проверки, сохраняет свое первоначальное значение, так что любые последующие запросы этого значения возвращают исходное значение, а не значение в действии. Это важно, потому что, если значение "abc" отправлено и не может быть преобразовано в int, мы хотим снова отобразить исходную строку ("abc"), а не значение int (вероятно, 0, что не имеет большого смысла пользователю).

  3. Validation Interceptor выполняет все запрошенные проверки (определенные в XML, аннотации или через validate() или же validateXXX() методы действия), добавив одно или несколько сообщений об ошибках в Field Errors для каждого поля, не проходящего один или несколько критериев проверки.

  4. 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 -->

Дополнительный вопрос:

Всякий раз, когда я добавляю алфавит в форму, он меняется на ноль...? Почему так?

Первоначальный ответ был: структура не смогла установить String в int поле при отправке запроса на сервер и при получении значения на получающейся странице, он вызывает Getter этой переменной; так как вы определили int и не Integer и int не может быть нулевым, он вернет значение по умолчанию для int: 0

Но я не помнил, что Conversion Interceptor утверждает (см. Пункт 2), чтобы сохранить исходные значения, чтобы предоставить их в последующих будущих запросах вместо значений Action (которые будут нулевыми или 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 Атрибут вообще сначала, чтобы убедиться, что он работает правильно, затем начните искать ошибку.

Другие вопросы по тегам